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

前言:
  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{
	@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运行过程中对这些基础设施的使用。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值