【Spring源码--AOP的实现】(一)AopProxy代理对象的创建

来源:互联网 发布:js在线编程 编辑:程序博客网 时间:2024/06/07 11:27

前言:

  1. 本篇是以ProxyFactoryBean的配置来讲的,这个是最能体现AOP思想的一个配置方式。后续会写下<aop:config>配置的源码,那个就稍微复杂点,我们后续再讲。
  2. 我在网上搜了下,很多举例都是通过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{@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);}}

那么到这里,通过使用AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy的代理对象。这个时候已经不会让应用直接调用target的方法实现了,而是先被AopProxy代理对象拦截,对于不同的Aopproxy代理对象的不同生成方法,拦截入口不同。比如:JDK使用的是InvocationHandler使用的是invoke入口,二Cglib使用的是设置好的callback回调。

如果把AOP的实现部分看成是由 基础设施准备和AOP运行辅助两个部分组成,那么这个第一部分是我们刚刚所探讨的内容。通过这个准备过程,把代理对象、拦截器(通知器)这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。




0 0
原创粉丝点击