spring的proxy-target-class详解
来源:互联网 发布:易语言聊天机器人源码 编辑:程序博客网 时间:2024/06/09 03:36
proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。首先说明下proxy-target-class="true"和proxy-target-class="false"的区别,为true则是基于类的代理将起作用(需要cglib库),为false或者省略这个属性,则标准的JDK 基于接口的代理将起作用。
proxy-target-class在spring事务、aop、缓存这几块都有设置,其作用都是一样的。
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/><aop:config proxy-target-class="true"><cache:annotation-driven proxy-target-class="true"/>
下面我们就aop对proxy-target-class属性进行分析
分析之前先把相关测试类列举下:
applicationContext-test-aop.xml文件
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> <!-- 激活spring的注解. --> <context:annotation-config /> <context:component-scan base-package="cn.sw.study.common.test.spring.aop" /> <aop:config proxy-target-class="true"> <aop:aspect id="log" ref="logHandler"> <aop:pointcut id="printLog" expression="execution(* cn.sw.study.common.test.spring.aop.service..*(..))" /> <aop:before method="LogBefore" pointcut-ref="printLog" /> <aop:after method="LogAfter" pointcut-ref="printLog" /> </aop:aspect> </aop:config></beans>UserService.java文件
package cn.sw.study.common.test.spring.aop.service;/** * 用户业务 * Created by shaowei on 2017/7/31. */public interface UserService { void addUser();}UserServiceImpl.java文件
package cn.sw.study.common.test.spring.aop.service;import org.springframework.stereotype.Service;/** * Created by shaowei on 2017/7/31. */@Servicepublic class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("add user"); }}LogHandler.java文件
package cn.sw.study.common.test.spring.aop;import org.springframework.stereotype.Component;/** * 日志处理类 * Created by shaowei on 2017/7/31. */@Componentpublic class LogHandler{ public void LogBefore() { System.out.println("Log before method"); } public void LogAfter() { System.out.println("Log after method"); }}AopTest.java文件
package cn.sw.study.common.test.spring.aop;import cn.sw.study.common.test.spring.aop.service.UserService;import cn.sw.study.common.test.spring.aop.service.UserServiceImpl;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * AOP测试类 * Created by shaowei on 2017/7/31. */public class AopTest { @Test public void testProxyTargetClass(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-test-aop.xml");// UserService userService = (UserService)context.getBean("userServiceImpl"); //proxy-target-class="true",为false时会报转换错误 UserServiceImpl userService = (UserServiceImpl)context.getBean("userServiceImpl"); userService.addUser(); }}
运行测试类,查看结果,可以正常运行,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属性的方法
private void configureAutoProxyCreator(ParserContext parserContext, Element element) { AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);}进入这个方法,再进入useClassProxyingIfNecessary方法则可以看到
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));if (proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}为true则调用forceAutoProxyCreatorToUseClassProxying方法,强制基于类来创建代理,从上面代码可以看出,不设置则默认为false
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); }}
此处可以看到,在bean定义对象中设置了proxyTargetClass属性,后面spring获取bean创建代理类的时候,会判断此属性类决定使用JdkDynamicAopProxy还是ObjenesisCglibAopProxy代理
打开DefaultAopProxyFactory类,查看createAopProxy方法public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); }}
hasNoUserSuppliedProxyInterfaces方法则说明即使你未声明proxy-target-class="true" ,但运行类没有继承接口,spring也会自动使用CGLIB代理。
总结:高版本spring自动根据运行类选择JDK或CGLIB代理,我们无需设置proxy-target-class属性,JDK动态代理是模拟接口实现的方式,cglib是模拟子类继承的方式,一般采用前者,因为前者效率高。后者不建议使用。
- spring的proxy-target-class详解
- spring proxy-target-class
- 【spring】proxy-target-class="true" 与proxy-target-class="false"的区别
- Spring AOP: proxy-target-class 值的意思
- Spring AOP: proxy-target-class 值的意思
- proxy-target-class 作用
- proxy-target-class="true"对Spring实例创建的影响
- spring->aop中proxy-target-class属性的含义以及动态代理机制
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- proxy-target-class="true" 与proxy-target-class="false"的区别
- JStorm与Storm源码分析(六)--收集器 IOutputCollector 、OutputCollector
- linux下oracle无图形化界面安装
- 小程序系列之布局
- javaAPI操作hdfs文件系统环境准备
- cfKey races(水)
- spring的proxy-target-class详解
- codevs 2488 绿豆蛙的归宿 拓扑+概率统计
- PHP 怎么计算二维数组里面某个值有几个重复了,是那几个,重复了几次
- Linex--shell脚本(二)条件判断之case、while循环
- 微信暑期活动总结
- Tensorflow中如何加载数据
- anko dsl preview plugin 错误
- 4.循环
- 田忌赛马