【Spring源码--AOP的实现】(一)AopProxy代理对象的创建
来源:互联网 发布:js在线编程 编辑:程序博客网 时间:2024/06/07 11:27
前言:
- 本篇是以ProxyFactoryBean的配置来讲的,这个是最能体现AOP思想的一个配置方式。后续会写下<aop:config>配置的源码,那个就稍微复杂点,我们后续再讲。
- 我在网上搜了下,很多举例都是通过main方法加载配置文件实现ProxyFactoryBean的,这里我是用页面掉用action实现该配置。原理是一样的,不知道大家有没有这样一种感觉,就是要找到web类型的案例才觉得有用,因为我们用的web太多了。
设计原理:
我们先来看下以ProxyFactory为中心的相关类的继承图:【这个图好丑,凑合着看下】
这里我们分别简单介绍下这几个类:
- ProxyConfig:可以看成一个数据基类,它可以为ProxyFactoryBean这样的子类提供配置属性。
- AdvisedSupport:封装了AOP对通知和通知器的相关操作,这些操作对于不同的AOP代理对象的生成都是一样的,但具体AOP对象的生成都是由子类完成的。
- ProxyCreatorSupport:看名字就可以猜到,它是一个辅助类,具体生成AOP对象依然是继续交给子类完成。
- AspectJProxyFactory:集成Spring和AspectJ的作用,适用于需要使用AspectJ的AOP应用。
- ProxyFactoryBean:Spring的AOP应用,可以在IOC中声明式配置。
- ProxyFactory:Spring的AOP应用,需要编程式使用。
配置ProxyFactoryBean
1)、Advisor通知器,这个通知器实现了对目标对象的增强行为,也就是Advice通知。
2)、定义ProxyFactoryBean:interceptorNames是指定义的通知器,可以有多个;target,需要增强的类,从源码上看只能有一个。
重点观察下,这里的参数是AopProxy,也就是说我们的createAopProxy方法已经生成了代理对象,那么我们就要看下这个代理对象时怎么生成的。
那么到这里,通过使用AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy的代理对象。这个时候已经不会让应用直接调用target的方法实现了,而是先被AopProxy代理对象拦截,对于不同的Aopproxy代理对象的不同生成方法,拦截入口不同。比如:JDK使用的是InvocationHandler使用的是invoke入口,二Cglib使用的是设置好的callback回调。
<bean name="userService" class="com.gh.test.service.impl.UserServiceImpl"></bean><bean name="userDao" class="com.gh.test.dao.impl.UserDaoImpl"></bean><!--配置Advice--><bean name="logAdvice" class="com.gh.test.aop.LoggerAdvice"></bean><!--配置ProxyFactoryBean--><bean name="aopmethod" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="interceptorNames"><list><value>logAdvice</value></list></property><property name="target" ref="userService"></property></bean>再来简单看下我们这个自定义的loggerAdvice:
public class LoggerAdvice implements MethodBeforeAdvice{@Overridepublic void before(Method method, Object[] args, Object target)throws Throwable {System.out.println("系统日志:"+(new Date())+":"+"调用了"+method.getName()+" :使用了参数"+(Arrays.toString(args)));}}具体的调用时页面出发action,页面及struts代码我就不贴了,简单看下action:
public class UserAction {public String addUser(){UserService userService = ApplicationContextUtil.getBean("aopmethod");BackUser user = new BackUser();user.setUsername("哈哈");user.setPassword("12345");userService.addUser(user);return "success";}}这样一个简单的web配置,已经可以实现对增加user时的UserSevice进行增强,在调用前输出日志:
系统日志:Tue Sep 06 19:36:02 CST 2016:调用了addUser :使用了参数[User[addtime=null , username=哈哈 , password=12345]]增加user
ProxyFactoryBean生成AopProxy代理对象
这里的ProxyFactoryBean是一个FactoryBean,对于FactoryBean这种Spring应用中经常出现的Bean的工作形式,前面的文章我已经讲过了FactoryBean的原理。从FactoryBean中获取对象,是通过getObject方法作为入口完成的,我们来看下这里的getObject方法。
代码1.1:ProxyFactoryBean的getObject方法
public Object getObject() throws BeansException { //初始化通知器链 initializeAdvisorChain(); //如果目标对象是单态模式 if (isSingleton()) { //调用获取单态模式对象的方法产生AOPProxy代理 return getSingletonInstance(); } //如果目标对象是原型模式 else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } //调用原型模式对象方法每次创建一个新的AOPProxy代理对象 return newPrototypeInstance(); } }这里面有三个方法,注释已经写的很清楚了,我们先来看initializeAdvisorChain方法,这里会有个标志位,如果已经初始化过,就不再初始化。来看下代码:
代码1.2:ProxyFactoryBean的initializeAdvisorChain方法
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { //如果通知器链已经被初始化,则直接返回,即通知器链只在第一次获取代理对象时产生 if (this.advisorChainInitialized) { return; } //如果ProxyFactoryBean中配置的连接器列名名称不为空 if (!ObjectUtils.isEmpty(this.interceptorNames)) { //如果没有Bean工厂(容器) if (this.beanFactory == null) { throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); } //全局通知器不能是通知器链中最后一个,除非显式使用属性指定了目标 if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { throw new AopConfigException("Target required after globals"); } //遍历通知器链,向容器添加通知器 for (String name : this.interceptorNames) { if (logger.isTraceEnabled()) { logger.trace("Configuring advisor or advice '" + name + "'"); } //如果通知器是全局的 if (name.endsWith(GLOBAL_SUFFIX)) { if (!(this.beanFactory instanceof ListableBeanFactory)) { throw new AopConfigException( "Can only use global advisors or interceptors with a ListableBeanFactory"); } //向容器中添加全局通知器 addGlobalAdvisor((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); } //如果通知器不是全局的 else { Object advice; //如果通知器是单态模式 if (this.singleton || this.beanFactory.isSingleton(name)) { //从容器获取单态模式的通知或者通知器 advice = this.beanFactory.getBean(name); } //如果通知器是原型模式 else { //创建一个新的通知或者通知器对象 advice = new PrototypePlaceholderAdvisor(name); } //添加通知器 addAdvisorOnChainCreation(advice, name); } } } //设置通知器链已初始化标识 this.advisorChainInitialized = true; }这里主要是对interceptorNames等元素的处理,我们继续看获取单例或多例的对象的具体代码:
代码1.3:ProxyFactoryBean的getSingletonInstance、newPrototypeInstance方法
// 获取一个单态模式的AOPProxy代理对象private synchronized Object getSingletonInstance() {// 如果单态模式的代理对象还未被创建if (this.singletonInstance == null) {// 获取代理的目标源this.targetSource = freshTargetSource();// 如果ProxyFactoryBean设置了自动探测接口属性,并且没有配置代理接且不是目标对象的直接代理类if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {// 获取代理对象的目标类Class targetClass = getTargetClass();if (targetClass == null) {throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");}// 设置代理对象的接口setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass,this.proxyClassLoader));}// 初始化共享的单态模式对象super.setFrozen(this.freezeProxy);// 调用ProxyFactory生成代理AOPProxy对象this.singletonInstance = getProxy(createAopProxy());}return this.singletonInstance;}// 获取一个原型模式的代理对象private synchronized Object newPrototypeInstance() {if (logger.isTraceEnabled()) {logger.trace("Creating copy of prototype ProxyFactoryBean config: "+ this);}// 根据当前的AOPProxyFactory获取一个创建代理的辅助类ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());// 获取一个刷新的目标源TargetSource targetSource = freshTargetSource();// 从当前对象中拷贝AOP的配置,为了保持原型模式对象的独立性,每次创建代理对象时都需要拷贝AOP的配置,以保证原型模式AOPProxy代理对象的独立性copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {// 设置代理接口copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));}copy.setFrozen(this.freezeProxy);if (logger.isTraceEnabled()) {logger.trace("Using ProxyCreatorSupport copy: " + copy);}// 调用ProxyFactory生成AOPProxy代理return getProxy(copy.createAopProxy());}单例多例的不同模式代码大家应该可以理解,我们重点看这么一个方法,getProxy(AopProxy)方法,我们来观察下这个方法
重点观察下,这里的参数是AopProxy,也就是说我们的createAopProxy方法已经生成了代理对象,那么我们就要看下这个代理对象时怎么生成的。
代码1.4:DefaultAopProxyFactory的createAopProxy方法
// 创建AOPProxy代理的入口方法protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}// 调用DefaultAopProxyFactory的创建AOPProxy代理的方法return getAopProxyFactory().createAopProxy(this);}// 创建AOP代理对象public AopProxy createAopProxy(AdvisedSupport config)throws AopConfigException {// 如果AOP使用显式优化,或者配置了目标类,或者只使用Spring支持的代理接口if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {// 获取AOP配置的目标类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.");}// 如果配置的AOP目标类是接口,则使用JDK动态代理机制来生成AOP代理if (targetClass.isInterface()) {return new JdkDynamicAopProxy(config);}// 如果AOP配置的目标类不是接口,则使用CGLIB的方式来生成AOP代理if (!cglibAvailable) {throw new AopConfigException("Cannot proxy target class because CGLIB2 is not available. "+ "Add CGLIB to the class path or specify proxy interfaces.");}return CglibProxyFactory.createCglibProxy(config);} else {return new JdkDynamicAopProxy(config);}}那么这里是根据了AOP目标类是否为接口来判断生成代理对象的方式,那么我们刚才配置的就是走jdk的动态代理模式。那么从上面的代码看到这个时候我们已经得到了一个AopProxy类,这个类并不是我们要的代理对象。那么具体它又是怎么取得代理对象,我们要从getProxy(AopProxy aopProxy)方法中去看。
JDK生成AopProxy对象
我们直接从getProxy方法进去就可以看到该方法。
代码1.5:JdkDynamicAopProxy类的getProxy方法
// 创建AOP代理对象public Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is "+ this.advised.getTargetSource());}// 获取AOPBeanFactory中配置的代理接口Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);// 查找代理目标的接口中是否定义equals()和hashCode()方法findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);// 使用JDK的动态代理机制创建AOP代理对象return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}具体内容也是比较简单,先取得代理对象的代理接口配置,然后调用Proxy的newProxyInstance方法。这里创建代理对象的时候,需要指明3个参数,一个是类加载器、一个是代理接口、另一个是Proxy回调方法所在的对象,这个对象需要实现InvocationHandler接口。这里JdkDynamicAopProxy本身就实现了该接口,所以可以使用this对象本身作为参数。
CGLIB生成AopProxy对象
这个代码相对多一点,主要内容呢就是对Enhancer对象进行各种配置,然后通过Enhancer对象去生成代理对象。来看代码
代码1.6:Cglib2AopProxy类的getProxy方法
public Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating CGLIB2 proxy: target source is "+ this.advised.getTargetSource());}try {// 从代理创建辅助类中获取在IoC容器中配置的目标对象Class rootClass = this.advised.getTargetClass();Assert.state(rootClass != null,"Target class must be available for creating a CGLIB proxy");// 将目标对象本身做为自己的基类Class proxySuperClass = rootClass;// 检查获取到的目标类是否是CGLIB产生的if (AopUtils.isCglibProxyClass(rootClass)) {// 如果目标类是有CGLIB产生的,获取目标类的基类proxySuperClass = rootClass.getSuperclass();// 获取目标类的接口Class[] additionalInterfaces = rootClass.getInterfaces();// 将目标类的接口添加到容器AOP代理创建辅助类的配置中for (Class additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface);}}// 校验代理基类validateClassIfNecessary(proxySuperClass);// 配置CGLIB的Enhancer类,Enhancer是CGLIB中的主要操作类Enhancer enhancer = createEnhancer();if (classLoader != null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader&& ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}// 设置enhancer的基类enhancer.setSuperclass(proxySuperClass);enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));// 设置enhancer的接口enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setInterceptDuringConstruction(false);// 设置enhancer的回调方法Callback[] callbacks = getCallbacks(rootClass);enhancer.setCallbacks(callbacks);// 将通知器中配置作为enhancer的方法过滤enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap,this.fixedInterceptorOffset));Class[] types = new Class[callbacks.length];for (int x = 0; x < types.length; x++) {types[x] = callbacks[x].getClass();}// 设置enhancer的回调类型enhancer.setCallbackTypes(types);// 创建代理对象Object proxy;if (this.constructorArgs != null) {proxy = enhancer.create(this.constructorArgTypes,this.constructorArgs);} else {proxy = enhancer.create();}return proxy;} catch (CodeGenerationException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class ["+ this.advised.getTargetClass()+ "]: "+ "Common causes of this problem include using a final class or a non-visible class",ex);} catch (IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class ["+ this.advised.getTargetClass()+ "]: "+ "Common causes of this problem include using a final class or a non-visible class",ex);} catch (Exception ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex);}}
如果把AOP的实现部分看成是由 基础设施准备和AOP运行辅助两个部分组成,那么这个第一部分是我们刚刚所探讨的内容。通过这个准备过程,把代理对象、拦截器(通知器)这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。
0 0
- 【Spring源码--AOP的实现】(一)AopProxy代理对象的创建
- Spring AOP的实现之建立AopProxy代理对象
- Spring源码分析----建立AopProxy代理对象和AOP拦截器的调用
- Spring Aop源码学习--Aop代理AopProxy
- Spring Aop原理分析(一) - 建立AopProxy代理对象
- Spring源码阅读4.2-Aspecjt AOP之代理对象的创建
- Spring Aop(十四)——Aop自动创建代理对象的原理
- 代理实现spring的AOP
- Spring AOP的实现原理之代理创建
- spring aop(五)--ProxyFactoryBean创建代理的实现
- Spring:AOP(一)生成代理对象
- spring aop实现过程之一代理对象的生成
- Spring AOP的实现机制(一)----- 动态代理
- SPRING源码学习之路(三)——<aop:config>自动代理的实现
- Spring AOP 代理对象的生成 part3
- Spring AOP-编程的方式创建代理类(ProxyFactoryBean)
- spring对AOP的支持(JDK的动态代理实现AOP和CGLIB实现AOP)
- spring生成代理对象的过程(AOP切面)
- 对于Java语言面向对象的初步认识
- BZOJ 1557: GC转移【贪心,然而果然特判更快
- JAVA 类型转换规则
- Network学习13_DNS报文格式
- 自定义控件 AttributeSet
- 【Spring源码--AOP的实现】(一)AopProxy代理对象的创建
- 微信公众平台开发入门教程
- Java面试题集(六)
- 第二周项目0-宣告“主权”
- 视频叠加文字
- Linux中的计划任务—Crontab调度重复执行的任务
- Fmod Studio event Random volume and Random pitch功能使用
- HDU饭卡
- qt做的软件的更新程序!