【Spring源码--AOP的实现】(一)AopProxy代理对象的创建
2016-09-06 18:53
711 查看
前言:
本篇是以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,需要增强的类,从源码上看只能有一个。
<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{ @Override public 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() failed throw new AopConfigException("Unexpected AOP exception", ex); } }
那么到这里,通过使用AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy的代理对象。这个时候已经不会让应用直接调用target的方法实现了,而是先被AopProxy代理对象拦截,对于不同的Aopproxy代理对象的不同生成方法,拦截入口不同。比如:JDK使用的是InvocationHandler使用的是invoke入口,二Cglib使用的是设置好的callback回调。
如果把AOP的实现部分看成是由 基础设施准备和AOP运行辅助两个部分组成,那么这个第一部分是我们刚刚所探讨的内容。通过这个准备过程,把代理对象、拦截器(通知器)这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。
相关文章推荐
- Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
- Spring3.1.0实现原理分析(九).AOP创建代理对象的过程
- Spring AOP 源码分析 - 创建代理对象
- Spring源码分析----建立AopProxy代理对象和AOP拦截器的调用
- Spring AOP 源码分析——创建代理对象
- Spring源码阅读4.2-Aspecjt AOP之代理对象的创建
- Spring AOP的实现之建立AopProxy代理对象
- Spring3.1.0实现原理分析(九).AOP之创建代理对象的过程
- Spring源码之创建AOP代理(补)
- Spring 源码分析(三) —— AOP(五)创建代理
- Spring aop 通过获取代理对象实现事务切换
- Spring Aop(十三)——ProxyFactoryBean创建代理对象
- SpringAOP源码解析之代理创建篇
- Spring AOP的实现原理之代理创建
- 黑马程序员--09.动态与代理AOP--06【动态代理实例化的过程升级--目标对象+系统功能的参数化】【实现类似Spring的可配置AOP框架】
- Spring AOP源码解析——AOP动态代理原理和实现方式
- spring aop(五)--ProxyFactoryBean创建代理的实现
- 【Spring源码--IOC容器的实现】(五)Bean对象的创建
- spring 源码探索 -- aop 标签解析和创建代理