SpringMVC 代理问题 [英] SpringMVC Proxy issue
问题描述
这几天我一直在努力寻找这个问题的答案,我希望有人能指出我正确的方向.我有一个使用 Java 配置的 SpringMVC 应用程序,在我尝试将 Apache-Shiro 集成到其中之前,我一直做得很好.我能够构建和运行我的测试.但是由于代理/CGLIB 问题,我的部署失败了.
I have been trying to find an answer to this problem for days, and I hope someone can point me in the right direction. I have a SpringMVC app that uses Java Configuration and I was doing fine until I tried to integrate Apache-Shiro into it. I am able to build and run my tests. But my deploy fails because of Proxy/CGLIB issues.
这是我在部署/重启时遇到的异常:
Here is the exception I get on deploy/restart:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'menuRepository': Post-processing of the FactoryBean's object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy69]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy69
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:165)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1454)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:442)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:550)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 55 more
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy69]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy69
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:217)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1625)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:162)
... 65 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy69
at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
... 72 more
这是我当前的设置:
pom.xml
<org.springframework.version>3.2.3.RELEASE</org.springframework.version>
<shiro.version>1.2.2</shiro.version>
<org.hibernate.version>4.1.7.Final</org.hibernate.version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.3.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>$3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.apache.shiro</groupId>-->
<!--<artifactId>shiro-aspectj</artifactId>-->
<!--<version>${shiro.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${org.hibernate.version}</version>
</dependency>
<!-- Hibernate metamodel annotation processor -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>1.1.1.Final</version>
</dependency>
...
</>
我使用这个网络配置:
public class EdmWebInitializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
private static final String DISPATCHER_SERVLET_MAPPING = "/*";
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new
AnnotationConfigWebApplicationContext();
//I have two @Configuration classes:
rootContext.register( EdmConfiguration.class, SecurityConfig.class );
// Manage the lifecycle of the root application context
servletContext.addListener( new ContextLoaderListener( rootContext ) );
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.setServletContext( servletContext );
dispatcherContext.setParent( rootContext );
// it seems I have to register the Configuration classes again or I can't @Autowire
dispatcherContext.register( EdmConfiguration.class, SecurityConfig.class );
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet( "dispatcher", new DispatcherServlet( dispatcherContext ) );
dispatcher.setLoadOnStartup( 1 );
dispatcher.addMapping( "/" );
servletContext.addFilter( "shiroFilter", new DelegatingFilterProxy( "shiroFilter", dispatcherContext ) )
.addMappingForUrlPatterns( null, false, "/*" );
}
}
这是我的主要配置类:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.company.product.service", "com.company.product.utility",
"com.company.product.controller", "com.company.product.utility.startup",
"com.company.product.security", "com.company.product.repository.people" })
@EnableTransactionManagement(proxyTargetClass=false)
@ImportResource({ "classpath:applicationContext.xml" })
@PropertySource({ "classpath:application.properties", "classpath:mail.properties" })
public class EdmConfiguration extends WebMvcConfigurationSupport {
@Resource
private Environment environment;
@Autowired
private org.apache.shiro.web.mgt.WebSecurityManager securityManager;
@Bean
public DataSource dataSource() {
BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_DRIVER ) );
dataSource.setJdbcUrl( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_URL ) );
dataSource.setUsername( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_USERNAME ) );
dataSource.setPassword( environment.getRequiredProperty( PROPERTY_NAME_DATABASE_PASSWORD ) );
return dataSource;
}
@Bean
public JpaTransactionManager transactionManager() throws ClassNotFoundException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() );
return transactionManager;
}
@Bean
public DelegatingFilterProxy springSecurityFilterChain() {
return new DelegatingFilterProxy();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource( dataSource() );
entityManagerFactoryBean.setPackagesToScan( environment
.getRequiredProperty( PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN ) );
entityManagerFactoryBean.setPersistenceProviderClass( HibernatePersistence.class );
Properties jpaProperties = new Properties();
...
entityManagerFactoryBean.setJpaProperties( jpaProperties );
return entityManagerFactoryBean;
}
@Bean
public PersistenceExceptionTranslator exTranslator() {
return new HibernateExceptionTranslator();
}
@Bean(initMethod = "init")
public StartupListener startupListener() {
return new StartupListener();
}
@Bean
public StandardPasswordEncoder encoder() {
return new org.springframework.security.crypto.password.StandardPasswordEncoder();
}
@Bean
public ShiroFilterFactoryBean shiroFilter() {
ShiroFilterFactoryBean shiroFilter = new org.apache.shiro.spring.web.ShiroFilterFactoryBean();
shiroFilter.setSecurityManager( securityManager);
shiroFilter.setLoginUrl( "/login" );
shiroFilter.setUnauthorizedUrl( "/" );
return shiroFilter;
}
@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
}
这是另一个配置类.正是添加这一点导致了代理问题.
And here is the other Configuration class. It is the addition of this that causes the proxy issues.
@Configuration
public class SecurityConfig {
@Bean
public SaltAwareJdbcRealm saltAwareJdbcRealm() {
return new SaltAwareJdbcRealm();
}
@Bean
public WebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm( saltAwareJdbcRealm() );
return securityManager;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod( "org.apache.shiro.SecurityUtils.setSecurityManager" );
methodInvokingFactoryBean.setArguments( new Object[]{ securityManager() } );
return methodInvokingFactoryBean;
}
@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authori
zationAttributeSourceAdvisor.setSecurityManager( securityManager() );
return authorizationAttributeSourceAdvisor;
}
}
违规类只是一个spring jparepository:
the offending class is just a spring jparepository:
public interface MenuRepository extends CrudRepository<Menu, Long>, JpaSpecificationExecutor<Menu> {
...}
我添加了 @EnableTransactionManagement(proxyTargetClass=false),我认为它可以解决代理问题,但显然不是.
I have added the @EnableTransactionManagement(proxyTargetClass=false) which I thought would address the Proxy issue but apparently isn't.
感谢您花时间阅读所有内容.
Thank you for your time in reading all this.
推荐答案
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy69
此异常表示,由于某些错误配置或应用 AOP 的多种方式,正在生成代理的代理.现在对于 JDK 动态代理,这不是问题,但是对于基于类的代理来说却是问题.因为 cglib 使类成为 final(如堆栈跟踪所示).
This exception indicates that, due to some misconfiguration or multiple ways of applying AOP, a proxy of a proxy is being generated. Now with JDK Dynamic Proxies this isn't a problem however with class based proxies it is. Because cglib makes the classes final (as indicated by the stacktrace).
您的配置有多种生成代理的方式,@EnableTransactionManagement
已经触发了 AutoProxyCreator
的注册.接下来,您将添加另一个.
Your configuration has multiple ways of generation proxies, @EnableTransactionManagement
triggers the registration of an AutoProxyCreator
already. Next you are adding another one.
这种情况下的解决方案是删除 DefaultAdvisorAutoProxyCreator
,因为已经有一个为您注册的实例.这将禁用代理代理.
The solution in this case is to remove the DefaultAdvisorAutoProxyCreator
as there is already an instance registered for you. This will disable proxying a proxy.
这篇关于SpringMVC 代理问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!