下面我们来看看 Spring 的 AOP 的一些相关代码是怎么得到 Proxy 的,让我们我们先看看 AOP 和 Spring AOP 的一些基本概念: Advice: 通知,制定在连接点做什么,在 Sping 中,他主要描述 Spring 围绕方法调用注入的额外的行为,Spring 提供的通知类型有:
代码语言:javascript复制1before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice
这些都是 Spring AOP 定义的接口类,具体的动作实现需要用户程序来完成。 Pointcut: 切点,其决定一个 advice 应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个 advice 作为目标的一组方法。Spring pointcut 通常意味着标示方法,可以选择一组方法调用作为 pointcut,Spring 提供了具体的切点来给用户使用,比如正则表达式切点 JdkRegexpMethodPointcut 通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut 中的对MethodMatcher 接口的实现来完成 pointcut 功能:
代码语言:javascript复制 1public final boolean matches(Method method, Class targetClass) {
2 //这里通过反射得到方法的全名
3 String patt = method.getDeclaringClass().getName() "." method.getName();
4 for (int i = 0; i < this.patterns.length; i ) {
5 // 这里是判断是否和方法名是否匹配的代码
6 boolean matched = matches(patt, i);
7 if (matched) {
8 for (int j = 0; j < this.excludedPatterns.length; j ) {
9 boolean excluded = matchesExclusion(patt, j);
10 if(excluded) {
11 return false;
12 }
13 }
14 return true;
15 }
16 }
17 return false;
18}
在 JDKRegexpMethodPointcut 中通过 JDK 中的正则表达式匹配来完成 pointcut 的最终确定:
代码语言:javascript复制1protected boolean matches(String pattern, int patternIndex) {
2 Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
3 return matcher.matches();
4}
Advisor: 当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 - advisor,定义应该在哪里应用哪个通知。Advisor 的实现有:DefaultPointcutAdvisor 他有两个属性 advice 和 pointcut 来让我们配置 advice和 pointcut。
接着我们就可以通过 ProxyFactoryBean 来配置我们的代理对象和方面行为,在 ProxyFactoryBean 中有 interceptorNames 来配置已经定义好的通知器-advisor,虽然这里的名字叫做 interceptNames,但实际上是供我们配置 advisor 的地方,具体的代理实现通过 JDK 的Proxy 或者 CGLIB 来完成。因为 ProxyFactoryBean 是一个 FactoryBean,在 ProxyFactoryBean 中我们通过 getObject()可以直接得到代理对象:
代码语言:javascript复制 1public Object getObject() throws BeansException {
2 //这里初始化通知器链
3 initializeAdvisorChain();
4 if (isSingleton()) {
5 //根据定义需要生成单件的 Proxy
6 return getSingletonInstance();
7 }else {
8 ...
9 //这里根据定义需要生成 Prototype 类型的 Proxy
10 return newPrototypeInstance();
11 }
12}
我们看看怎样生成单件的代理对象:
代码语言:javascript复制 1private synchronized Object getSingletonInstance() {
2 if (this.singletonInstance == null) {
3 this.targetSource = freshTargetSource();
4 if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
5 // 这里设置代理对象的接口
6 setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));
7 }
8 // Eagerly initialize the shared singleton instance.
9 super.setFrozen(this.freezeProxy);
10 // 注意这里的方法会使用 ProxyFactory 来生成我们需要的 Proxy
11 this.singletonInstance = getProxy(createAopProxy());
12 // We must listen to superclass advice change events to recache the singleton
13 // instance if necessary.
14 addListener(this);
15 }
16 return this.singletonInstance;
17}
18
19//使用 createAopProxy 放回的 AopProxy 来得到代理对象。
20protected Object getProxy(AopProxy aopProxy) {
21 return aopProxy.getProxy(this.beanClassLoader);
22}
ProxyFactoryBean 的父类是 AdvisedSupport,Spring 使用 AopProxy 接口把 AOP 代理的实现与框架的其他部分分离开来;在AdvisedSupport 中通过这样的方式来得到 AopProxy,当然这里需要得到 AopProxyFactory 的帮助 - 下面我们看到 Spring 为我们提供的实现,来帮助我们方便的从 JDK 或者 cglib 中得到我们想要的代理对象:
代码语言:javascript复制1protected synchronized AopProxy createAopProxy() {
2 if (!this.isActive) {
3 activate();
4 }
5 return getAopProxyFactory().createAopProxy(this);
6}
而在 ProxyConfig 中对使用的 AopProxyFactory 做了定义:
代码语言:javascript复制1//这个 DefaultAopProxyFactory 是 Spring 用来生成 AopProxy 的地方,
2//当然了它包含 JDK 和 Cglib 两种实现方式。
3private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
其中在 DefaultAopProxyFactory 中是这样生成 AopProxy 的:
代码语言:javascript复制 1public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
2 //首先考虑使用 cglib 来实现代理对象,当然如果同时目标对象不是接口的实现类的话
3 if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
4 advisedSupport.getProxiedInterfaces().length == 0) {
5 //这里判断如果不存在 cglib 库,直接抛出异常。
6 if (!cglibAvailable) {
7 throw new AopConfigException(
8 "Cannot proxy target class because CGLIB2 is not available. "
9 "Add CGLIB to the class path or specify proxy interfaces.");
10 }
11 // 这里使用 Cglib 来生成 Proxy,如果 target 不是接口的实现的话,返回 cglib 类型的 AopProxy
12 return CglibProxyFactory.createCglibProxy(advisedSupport);
13 }
14 else {
15 // 这里使用 JDK 来生成 Proxy,返回 JDK 类型的 AopProxy
16 return new JdkDynamicAopProxy(advisedSupport);
17 }
18}
于是我们就可以看到其中的代理对象可以由 JDK 或者 Cglib 来生成,我们看到 JdkDynamicAopProxy 类和 Cglib2AopProxy 都实现的是AopProxy 的接口,在 JdkDynamicAopProxy 实现中我们可以看到 Proxy 是怎样生成的:
代码语言:javascript复制 1public Object getProxy(ClassLoader classLoader) {
2 if (logger.isDebugEnabled()) {
3 Class targetClass = this.advised.getTargetSource().getTargetClass();
4 logger.debug("Creating JDK dynamic proxy"
5 (targetClass != null ? " for [" targetClass.getName() "]" : ""));
6 }
7 Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
8 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
9 //这里我们调用 JDK Proxy 来生成需要的 Proxy 实例
10 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
11}
这样用 Proxy 包装 target 之后,通过 ProxyFactoryBean 得到对其方法的调用就被 Proxy 拦截了, ProxyFactoryBean 的 getObject()方法得到的实际上是一个 Proxy 了,我们的 target 对象已经被封装了。对 ProxyFactoryBean 这个工厂 bean 而言,其生产出来的对象是封装了目标对象的代理对象