Spring Boot 和 Proguard

Posted

技术标签:

【中文标题】Spring Boot 和 Proguard【英文标题】:Spring Boot and Proguard 【发布时间】:2017-10-15 12:06:57 【问题描述】:

我有一个简单的 Spring Boot 1.5.3 应用程序,我试图使用 proguard-maven-plugin 与 Proguard 5.x 混淆。我有以下proguard.conf

-injars ../$FINAL_NAME$/WEB-INF/lib/$FINAL_NAME$.jar

-outjars ./

-optimizations !class/marking/final
-dontoptimize

-adaptresourcefilenames **.properties
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF

-dontshrink
-dontoptimize
-dontobfuscate
-dontusemixedcaseclassnames
-dontpreverify
-verbose

-keep public class com.test.blah.OnboardingApp 
  public static void main(java.lang.String[]);

-keep public class * extends org.springframework.boot.web.support.SpringBootServletInitializer

-keep class com.test.blah**.dto.** 
  void set*(***);
  *** get*();


-keepclassmembers class * 
  @org.springframework.beans.factory.annotation.Autowired *;
  @org.springframework.beans.factory.annotation.Qualifier *;
  @org.springframework.beans.factory.annotation.Value *;
  @org.springframework.beans.factory.annotation.Required *;
  @org.springframework.context.annotation.Bean *;
  @org.springframework.context.annotation.Primary *;
  @org.springframework.boot.context.properties.ConfigurationProperties *;
  @org.springframework.boot.context.properties.EnableConfigurationProperties *;
  @javax.inject.Inject *;
  @javax.annotation.PostConstruct *;
  @javax.annotation.PreDestroy *;


-keep @org.springframework.stereotype.Service class *
-keep @org.springframework.stereotype.Controller class *
-keep @org.springframework.stereotype.Component class *
-keep @org.springframework.stereotype.Repository class *
-keep @org.springframework.cache.annotation.EnableCaching class *
-keep @org.springframework.context.annotation.Configuration class *
-keep @org.springframework.boot.context.properties.ConfigurationProperties class *
-keep @org.springframework.boot.autoconfigure.SpringBootApplication class *

-allowaccessmodification
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod
-keepattributes *Annotation*
-keepattributes Signature
-keepattributes Exceptions
-keepattributes InnerClasses

-keepparameternames
-keepdirectories com.test.blah
-keepdirectories org.springframework.boot.autoconfigure

-keepclassmembernames class * 
  java.lang.Class class$(java.lang.String);
  java.lang.Class class$(java.lang.String, boolean);


-keepclassmembers enum * 
  public static **[] values();
  public static ** valueOf(java.lang.String);
  public static ** fromValue(java.lang.String);


-keepnames class * implements java.io.Serializable
-keepclassmembernames public class com.test.blah.config.liquibase.AsyncSpringLiquibase

-keepclassmembers class * implements java.io.Serializable 
  static final long serialVersionUID;
  private static final java.io.ObjectStreamField[] serialPersistentFields;
  !static !transient <fields>;
  !private <fields>;
  !private <methods>;
  private void writeObject(java.io.ObjectOutputStream);
  private void readObject(java.io.ObjectInputStream);
  java.lang.Object writeReplace();
  java.lang.Object readResolve();


-keepclassmembers class * 
  @org.springframework.beans.factory.annotation.Autowired <fields>;
  @org.springframework.beans.factory.annotation.Autowired <methods>;
  @org.springframework.security.access.prepost.PreAuthorize <methods>;

我正在加载proguard.conf

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>$maven-antrun-plugin.version</version>
    <executions>
        <execution>
            <phase>process-classes</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <target>
                    <mkdir dir="$project.build.directory/proguarded" />
                    <copy file="proguard.conf" todir="target/proguarded" />
                    <replace file="$project.build.directory/proguarded/proguard.conf"
                             token="$FINAL_NAME$" value="$project.build.finalName" />
                </target>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>com.github.wvengen</groupId>
    <artifactId>proguard-maven-plugin</artifactId>
    <version>$proguard-maven-plugin.version</version>
    <executions>
        <execution>
            <phase>prepare-package</phase>
            <goals>
                <goal>proguard</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <proguardInclude>$project.build.directory/proguarded/proguard.conf</proguardInclude>
        <libs>
            <lib>$java.home/lib/rt.jar</lib>
            <lib>$java.home/lib/jce.jar</lib>
            <lib>$java.home/lib/jsse.jar</lib>
        </libs>
    </configuration>
</plugin>

生成war 文件工件没有问题。但是,当我部署到 tomcat 实例时,出现以下错误,

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Cannot find changelog location: class path resource [db/changelog/db.changelog-master.yaml] (please add changelog or check your Liquibase configuration)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:137)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:372)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:856)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
    at org.springframework.boot.web.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:151)
    at org.springframework.boot.web.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:131)
    at org.springframework.boot.web.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:86)
    at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    ... 10 more
Caused by: java.lang.IllegalStateException: Cannot find changelog location: class path resource [db/changelog/db.changelog-master.yaml] (please add changelog or check your Liquibase configuration)
    at org.springframework.util.Assert.state(Assert.java:70)
    at org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration$LiquibaseConfiguration.checkChangelogExists(LiquibaseAutoConfiguration.java:92)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134)
    ... 42 more

在我的应用程序中,我正在加载 Liquibase bean,

@Configuration("databaseConfiguration")
@EnableJpaRepositories("com.test.blah.repository")
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
@EnableTransactionManagement
@EnableElasticsearchRepositories("com.test.blah.repository.search")
public class DatabaseConfiguration 

    private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);

    @Inject
    private Environment env;

    @Bean
    public SpringLiquibase liquibase(DataSource dataSource, LiquibaseProperties liquibaseProperties) 
        // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
        SpringLiquibase liquibase = new AsyncSpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog("classpath:config/liquibase/master.xml");
        liquibase.setContexts(liquibaseProperties.getContexts());
        liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
        liquibase.setDropFirst(liquibaseProperties.isDropFirst());
        if (env.acceptsProfiles(Constants.SPRING_PROFILE_NO_LIQUIBASE)) 
            liquibase.setShouldRun(false);
         else 
            liquibase.setShouldRun(liquibaseProperties.isEnabled());
            log.debug("Configuring Liquibase");
        
        return liquibase;
    

谁能告诉我为什么我看到错误?

【问题讨论】:

【参考方案1】:

诀窍是使用-keepdirectories 中提到的https://www.guardsquare.com/en/proguard/manual/usage#iooptions

如果其他人遇到此问题,我只是将其添加到上述 proguard.conf 并删除了过滤器。

所以不是,

-keepdirectories com.test.blah
-keepdirectories org.springframework.boot.autoconfigure

我有,

-keepdirectories

这似乎涵盖了所有目录。

【讨论】:

非常感谢!!帮了我很大的忙

以上是关于Spring Boot 和 Proguard的主要内容,如果未能解决你的问题,请参考以下文章

spring-boot-starter-web 和 spring-boot-starter-webflux 不能一起工作吗?

Spring Boot系列 Spring Boot介绍和基础POM文件

Spring Boot:Spring Boot整合Logback和PageHelper

spring-boot-starter-jta-atomikos 和 spring-boot-starter-batch

《02.Spring Boot连载:Spring Boot实战.Spring Boot核心原理剖析》

Spring boot 梳理 - Spring Boot 属性配置和使用(转)