spring的proxy-target-class详解

http://blog.csdn.net/shaoweijava/article/details/76474652


proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。首先说明下proxy-target-class="true"和proxy-target-class="false"的区别,为true则是基于类的代理将起作用(需要cglib库),为false或者省略这个属性,则标准的JDK 基于接口的代理将起作用。
proxy-target-class在spring事务、aop、缓存这几块都有设置,其作用都是一样的。

[html]  view plain  copy
  1. <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>  
  2. <aop:config proxy-target-class="true">  
  3. <cache:annotation-driven proxy-target-class="true"/>  

下面我们就aop对proxy-target-class属性进行分析

分析之前先把相关测试类列举下:

applicationContext-test-aop.xml文件

[html]  view plain  copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
  5.        xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"  
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
  7.                            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  8.                            http://www.springframework.org/schema/context  
  9.                            http://www.springframework.org/schema/context/spring-context-3.2.xsd  
  10.                            http://www.springframework.org/schema/aop  
  11.                            http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">  
  12.   
  13.     <!-- 激活spring的注解. -->  
  14.     <context:annotation-config />  
  15.   
  16.     <context:component-scan base-package="cn.sw.study.common.test.spring.aop" />  
  17.   
  18.     <aop:config proxy-target-class="true">  
  19.         <aop:aspect id="log" ref="logHandler">  
  20.             <aop:pointcut id="printLog" expression="execution(* cn.sw.study.common.test.spring.aop.service..*(..))" />  
  21.             <aop:before method="LogBefore" pointcut-ref="printLog" />  
  22.             <aop:after method="LogAfter" pointcut-ref="printLog" />  
  23.         </aop:aspect>  
  24.     </aop:config>  
  25. </beans>  
UserService.java文件

[java]  view plain  copy
  1. package cn.sw.study.common.test.spring.aop.service;  
  2.   
  3. /** 
  4.  * 用户业务 
  5.  * Created by shaowei on 2017/7/31. 
  6.  */  
  7. public interface UserService {  
  8.     void addUser();  
  9. }  
UserServiceImpl.java文件
[java]  view plain  copy
  1. package cn.sw.study.common.test.spring.aop.service;  
  2.   
  3. import org.springframework.stereotype.Service;  
  4.   
  5. /** 
  6.  * Created by shaowei on 2017/7/31. 
  7.  */  
  8. @Service  
  9. public class UserServiceImpl implements UserService {  
  10.     @Override  
  11.     public void addUser() {  
  12.         System.out.println("add user");  
  13.     }  
  14. }  
LogHandler.java文件

[java]  view plain  copy
  1. package cn.sw.study.common.test.spring.aop;  
  2.   
  3. import org.springframework.stereotype.Component;  
  4.   
  5. /** 
  6.  * 日志处理类 
  7.  * Created by shaowei on 2017/7/31. 
  8.  */  
  9. @Component  
  10. public class LogHandler  
  11. {  
  12.     public void LogBefore()  
  13.     {  
  14.         System.out.println("Log before method");  
  15.     }  
  16.   
  17.     public void LogAfter()  
  18.     {  
  19.         System.out.println("Log after method");  
  20.     }  
  21. }  
AopTest.java文件

[java]  view plain  copy
  1. package cn.sw.study.common.test.spring.aop;  
  2.   
  3. import cn.sw.study.common.test.spring.aop.service.UserService;  
  4. import cn.sw.study.common.test.spring.aop.service.UserServiceImpl;  
  5. import org.junit.Test;  
  6. import org.springframework.context.ApplicationContext;  
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  8.   
  9. /** 
  10.  * AOP测试类 
  11.  * Created by shaowei on 2017/7/31. 
  12.  */  
  13. public class AopTest {  
  14.     @Test  
  15.     public void testProxyTargetClass(){  
  16.         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-test-aop.xml");  
  17. //        UserService userService = (UserService)context.getBean("userServiceImpl");  
  18.   
  19.         //proxy-target-class="true",为false时会报转换错误  
  20.         UserServiceImpl userService = (UserServiceImpl)context.getBean("userServiceImpl");  
  21.         userService.addUser();  
  22.     }  
  23. }  

运行测试类,查看结果,可以正常运行,aop处理类也正常被调用

此时修改proxy-target-class="false",则报错

java.lang.ClassCastException:com.sun.proxy.$Proxy9 cannot be cast to

cn.sw.study.common.test.spring.aop.service.UserServiceImpl

下面我们来详细的分析下proxy-target-class属性

首先查看sping的aop依赖包,下载源码文件,找到spring.handlers文件


打开文件可以看到

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

AopNamespaceHandler类,就是spring解析<aop:configproxy-target-class="true">配置的入口,打开这个类,则可以看到init方法里注册了ConfigBeanDefinitionParser类来解析,这个类则是实际解析<aop:config proxy-target-class="true">的类

registerBeanDefinitionParser("config",new ConfigBeanDefinitionParser());

打开这个类搜索proxy-target-class,则可以看到configureAutoProxyCreator方法,这个方法则是解析proxy-target-class属性的方法

[java]  view plain  copy
  1. private void configureAutoProxyCreator(ParserContext parserContext, Element element) {  
  2.    AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);  
  3. }  
进入这个方法,再进入useClassProxyingIfNecessary方法则可以看到
[java]  view plain  copy
  1. boolean proxyTargetClass =   
  2. Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));  
  3. if (proxyTargetClass) {  
  4.    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);  
  5. }  
为true则调用forceAutoProxyCreatorToUseClassProxying方法,强制基于类来创建代理,从上面代码可以看出,不设置则默认为false
[java]  view plain  copy
  1. public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {  
  2.    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {  
  3.       BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);  
  4.       definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);  
  5.    }  
  6. }  

此处可以看到,在bean定义对象中设置了proxyTargetClass属性,后面spring获取bean创建代理类的时候,会判断此属性类决定使用JdkDynamicAopProxy还是ObjenesisCglibAopProxy代理

打开DefaultAopProxyFactory类,查看createAopProxy方法

[java]  view plain  copy
  1. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {  
  2.    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {  
  3.       Class<?> targetClass = config.getTargetClass();  
  4.       if (targetClass == null) {  
  5.          throw new AopConfigException("TargetSource cannot determine target class: " +  
  6.                "Either an interface or a target is required for proxy creation.");  
  7.       }  
  8.       if (targetClass.isInterface()) {  
  9.          return new JdkDynamicAopProxy(config);  
  10.       }  
  11.       return new ObjenesisCglibAopProxy(config);  
  12.    }  
  13.    else {  
  14.       return new JdkDynamicAopProxy(config);  
  15.    }  
  16. }  

hasNoUserSuppliedProxyInterfaces方法则说明即使你未声明proxy-target-class="true" ,但运行类没有继承接口,spring也会自动使用CGLIB代理。

总结:高版本spring自动根据运行类选择JDK或CGLIB代理,我们无需设置proxy-target-class属性,JDK动态代理是模拟接口实现的方式,cglib是模拟子类继承的方式,一般采用前者,因为前者效率高。后者不建议使用。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值