Spring AOP proxy代理生成

1、Spring AOP几个概念阐述

1.通知(Advice):

通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。

2.连接点(Joinpoint):

程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。

3.切入点(Pointcut)

通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,Spring中允许我们方便的用正则表达式来指定

4.切面(Aspect)

通知和切入点共同组成了切面:时间、地点和要发生的“故事”

5.引入(Introduction)

引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)

6.目标(Target)

即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)

7.代理(proxy)

应用通知的对象,详细内容参见设计模式里面的代理模式

8.织入(Weaving)

把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:

(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器

(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码

(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术

9.通知器(Advisor)

定义应该使用哪个通知(advice)并在哪个关注点(pointcut)使用它,也就是通过Advisor把advice以及pointcut结合起来。

在spring中一个典型的advisor就是DefaultPointcutAdvisor,如下代码所示:

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {

	private Pointcut pointcut = Pointcut.TRUE;

	
	/**
	 * Create a DefaultPointcutAdvisor, specifying Pointcut and Advice.
	 * @param pointcut the Pointcut targeting the Advice
	 * @param advice the Advice to run when Pointcut matches
	 */
	public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
		this.pointcut = pointcut;
		setAdvice(advice);
	}

它的两个属性就是pointcut以及advice,这里pointcut的实现是一个典型的懒汉单例模式实现,看其代码如下:

class TruePointcut implements Pointcut, Serializable {
	
	public static final TruePointcut INSTANCE = new TruePointcut();
	
	/**
	 * Enforce Singleton pattern.
	 */
	private TruePointcut() {
	}

使用static变量确保其只会被初始化一次,同时将类的构造函数设置为私有也保证了在当前的TruePointcut当中。

在pointcut当中有两个方法分别是classfilter和methodMatcher,这两个对象实现也是类似的单例模式。单例模式确保了资源的单一性,在这里使用单例模式有点作为util使用的含义。

2、AOPProxy代理对象的建立

在spring的AOP实现原理中一个重要的设计模式就是代理模式,那么代理模式里面最重要的一个点就是proxy,这里就阐述下这个proxy的建立过程。

在这个继承关系中,最底层的三个proxy类都有共同的三个基类: ProxyConfig、AdvisedSupport、ProxyCreatorSupport。

ProxyConfig:可以看做是一个数据基类,它为最底层的三个子类提供配置属性。

AdvisedSupport:封装了AOP对通知及通知器的相关操作,对于不同的aop代理对象的生成是一样的,对于具体的aop对象的创建就交给子类去操作。

ProxyCreatorSupport:是子类创建aop对象的辅助类。

 

AOP proxy创建时序图

从时序图可以看出首先是初始化advisorchain,就是从defaultListableBeanFactory中获取advisor的配置信息,并将它加入到一个List当中。主要代码逻辑如下:

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 {
					// If we get here, we need to add a named interceptor.
					// We must check if it's a singleton or prototype.
					Object advice;
					if (this.singleton || this.beanFactory.isSingleton(name)) {
						// Add the real Advisor/Advice to the chain.
						advice = this.beanFactory.getBean(name);
					}
					else {
						// It's a prototype Advice or Advisor: replace with a prototype.
						// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
						advice = new PrototypePlaceholderAdvisor(name);
					}
					addAdvisorOnChainCreation(advice, name);
				}
			}

遍历interceptorNames,再依据name去ioc容器中查找到相应对象并且添加。如果非全局切面,那么就查找单个对应切面的类,并且判断是否是单例,如果是单例就直接从容器中获取,如果不是单例就额外处理。最后添加到advisor的chain当中。

接下来就是生成单例的代理对象:

private synchronized ObjectgetSingletonInstance() {
                   if(this.singletonInstance == null) {
                            this.targetSource= freshTargetSource();
                            if(this.autodetectInterfaces && getProxiedInterfaces().length == 0&& !isProxyTargetClass()) {
                                     //Rely on AOP infrastructure to tell us what interfaces to proxy.
                                     ClasstargetClass = getTargetClass();
                                     if(targetClass == null) {
                                               thrownew FactoryBeanNotInitializedException("Cannot determine target class forproxy");
                                     }
                                     setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass,this.proxyClassLoader));
                            }
                            //Initialize the shared singleton instance.
                            super.setFrozen(this.freezeProxy);
                            this.singletonInstance= getProxy(createAopProxy());
                   }
                   returnthis.singletonInstance;
         }

首先根据aop框架获取代理的接口,并设置代理接口,之后就是获取代理类。从上面的时序图也可以看到到了aopproxy的创建。

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);
			}
			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);
		}
	}

创建首先判断是代理对象是否是接口,是接口的就使用jdk动态创建,其余的就采用cglib动态创建。其实最终就是创建一个Cglib2AopProxy或JdkDynamicAopProxy。也就是说着一步就是创建一个aopproxy的对象,接下来就是依据这个对象去生成我们需要的代理类。就是getproxy的过程。

JDK生成proxy对象的过程

public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

首先使用上面一步初始化设置的JdkDynamicAopProxy时设置的advised来加载proxy的接口,并依据这个实际接口和classload来实例化一个实际对象,具体的实现是Proxy.newProxyInstance(classLoader, proxiedInterfaces, this).在jdk的代理生成对象时,只需要传递一个InvocationHandler给到proxy,它的方法被调用时就会触发InvocationHandler的invoke方法,这个invoke方法的重点逻辑如下:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
			if (chain.isEmpty()) {
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
			}
			else {
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				retVal = invocation.proceed();
			}

invocation.proceed();就会将chain里面的切面执行到。

CGLIB的proxy创建:

// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setInterceptDuringConstruction(false);

			Callback[] callbacks = getCallbacks(rootClass);
			enhancer.setCallbacks(callbacks);
			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.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
			Object proxy;
			if (this.constructorArgs != null) {
				proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
			}
			else {
				proxy = enhancer.create();
			}

			return proxy;

就是使用enhance来设置Callbacks,当method被触发时。这些回调会被触发执行。所以他们的基本原理是相同的,只是jdk的是包装在里面进行invoke回调,而cglib的是显式的设置回调。

3、AOPProxy的设计模式

在aopproxy的设计中上面已经说到主要采用了代理模式。代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。代理模式的uml图如下:

在aopproxy中所谓的proxy就是aopproxy所生成的各类系统的注入对象,而request就是对象定义的切点,在这个切点被调用的时候首先会被aopproxy所生成的一个代理对象所捕获,先需要执行aopproxy在配置中所定义的advice,例如dobefore,doafter或dothrows等等。而这个执行过程对于客户端调用来说是透明的。

 

代理模式的优点:

能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。

 

代理模式的缺点

由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

实现代理模式需要额外的工作,有些代理模式的实现非常复杂。









  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值