Spring源代码分析(10)---ProxyFactoryBean(旁敲侧击的AOP时代终于来临)

原创 2008年10月02日 14:40:00
我们知道,AOP是面向切面编程,在java领域的AOP中,最著名莫过于牛逼哄哄的AspectJ了,我们在前几节的源码分析中,也复习了一下动态代理的知识,在那里,我们采用了几种手段来实现切面效果以及他们之间的区别和利弊;

从这一节,我们来分析一下Spring中的Aop的实现细节;

首先,我们先来看一个Spring AOP的例子:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
  5.     <bean id="name" name="name" class="org.corey.demo.Name"
  6.         abstract="false" lazy-init="default" autowire="default"
  7.         dependency-check="default">
  8.         <constructor-arg value="cui" />
  9.         <constructor-arg value="chizhou"></constructor-arg>
  10.     </bean>
  11.     <bean id="person" name="person" class="org.corey.demo.Person">
  12.         <property name="name" ref="name"></property>
  13.     </bean>
  14.     <bean name="advice" id="advice" class="org.syna.demo.BeforeAdvice"></bean>
  15.     <bean name="pointcut" id="pointcut"
  16.         class="org.springframework.aop.support.NameMatchMethodPointcut">
  17.         <property name="mappedName">
  18.             <value>*say</value>
  19.         </property>
  20.     </bean>
  21.     <bean id="advisor" name="advisor"
  22.         class="org.springframework.aop.support.DefaultPointcutAdvisor">
  23.         <property name="advice">
  24.             <ref local="advice" />
  25.         </property>
  26.         <property name="pointcut">
  27.             <ref local="pointcut" />
  28.         </property>
  29.     </bean>
  30.     <bean name="proxyBean"
  31.         class="org.springframework.aop.framework.ProxyFactoryBean">
  32.         <property name="target">
  33.             <ref local="person" />
  34.         </property>
  35.         <property name="interceptorNames">
  36.             <list>
  37.                 <idref local="advisor" />
  38.             </list>
  39.         </property>
  40.     </bean>
装备:
  1. package org.syna.demo;
  2. import java.lang.reflect.Method;
  3. import org.springframework.aop.MethodBeforeAdvice;
  4. public class BeforeAdvice implements MethodBeforeAdvice {
  5.     public void before(Method arg0, Object[] arg1, Object arg2)
  6.             throws Throwable {
  7.         System.out.println("before logging");
  8.     }
  9. }

  1. package org.corey.demo;
  2. public interface IPerson {
  3.     public Name getName();
  4.     public void setName(Name name);
  5.     public void setAddress(String address);
  6.     public String getAddress();
  7.     
  8.     public void say();
  9. }
  1. package org.corey.demo;
  2. public class Person implements IPerson {
  3.     private String name2;
  4.     public void setBeanName(String name) {
  5.         System.out.println("set name aware");
  6.         this.name2 = name;
  7.     }
  8.     private Name name;
  9.     private String address;
  10.     public Person() {
  11.     }
  12.     public Person(Name name, String address) {
  13.         this.name = name;
  14.         this.address = address;
  15.     }
  16.     public Name getName() {
  17.         return name;
  18.     }
  19.     public void setName(Name name) {
  20.         System.out.println("set name field");
  21.         this.name = name;
  22.     }
  23.     public String getAddress() {
  24.         return address;
  25.     }
  26.     public void setAddress(String address) {
  27.         this.address = address;
  28.     }
  29.     
  30.     public void say(){
  31.         System.out.println("say");
  32.     }
  33. }

  1. package org.syna.demo;
  2. import org.corey.demo.IPerson;
  3. import org.corey.demo.Person;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class Demo {
  7.     /**
  8.      * @param args
  9.      */
  10.     public static void main(String[] args) {
  11.         ApplicationContext ac = new ClassPathXmlApplicationContext(
  12.                 "applicationContext.xml");
  13.         IPerson person=(IPerson)ac.getBean("proxyBean");
  14.         person.say();
  15.     }
  16. }


console:

set name field
before logging   //这就是切面输出;
say


从上述代码,我们可见,我们主要的应用到了advice,advisor,pointcut,还有ProxyFactoryBean类,proxyFactoryBean继承于FactoryBean接口,这个接口的神奇我们在前一节就已经详细的分析过了,那么,我们就从这个接口来分析一下,我们是怎么从FactoryBean的getObject()方法取得代理对象的,以及这个代理对象是如何生成的;




可见ProxyFactoryBean继承了图示中的几个接口和类,他们分别的作用是

BeanFactoryAware:BeanFactory的回调接口,可以在ProxyFactoryBean类中获取当前BeanFactory;

AdvisedSupportListener是监听ActionSupport的监听接口,是一个监听者;

FactoryBean:如同前一节所解释的;

AdvisedSupport:提供了有关这个代理的一些详细信息:比如当前代理类代理的是那一个类等等;



我们会在ProxyFactoryBean中设置如下几个属性:
1):代理类的实现的接口(可选);
  1.     public void setProxyInterfaces(String[] interfaceNames) throws ClassNotFoundException {
  2.         Class[] interfaces = AopUtils.toInterfaceArray(interfaceNames);
  3.         setInterfaces(interfaces);
  4.     }
2):advisor类的名字,从这个我们可以知道代理规则;
  1.     public void setInterceptorNames(String[] interceptorNames) {
  2.         this.interceptorNames = interceptorNames;
  3.     }
3):代理类的名字;
  1.     public void setTargetName(String targetName) {
  2.         this.targetName = targetName;
  3.     }


然后我们来分析一下getObject()方法:
  1. public Object getObject() throws BeansException {
  2.         if (isSingleton()) {
  3.             return getSingletonInstance();
  4.         }
  5.         else {
  6.             if (this.targetName == null) {
  7.                 logger.warn("Using non-singleton proxies with singleton targets is often undesirable." +
  8.                         "Enable prototype proxies by setting the 'targetName' property.");
  9.             }
  10.             return newPrototypeInstance();
  11.         }
  12.     }
从这个方法,我们可见,ProxyBeanFactory根据上述信息给我们构造了一个PrototypeInstance();

  1. private synchronized Object newPrototypeInstance() {
  2.         // In the case of a prototype, we need to give the proxy
  3.         // an independent instance of the configuration.
  4.         // In this case, no proxy will have an instance of this object's configuration,
  5.         // but will have an independent copy.
  6.         if (logger.isDebugEnabled()) {
  7.             logger.debug("Creating copy of prototype ProxyFactoryBean config: " + this);
  8.         }
  9.         AdvisedSupport copy = new AdvisedSupport();
  10.         // The copy needs a fresh advisor chain, and a fresh TargetSource.
  11.         TargetSource targetSource = freshTargetSource();
  12.         copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
  13.         if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
  14.             // Rely on AOP infrastructure to tell us what interfaces to proxy.
  15.             copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));
  16.         }
  17.         copy.setFrozen(this.freezeProxy);
  18.         if (logger.isDebugEnabled()) {
  19.             logger.debug("Copy has config: " + copy);
  20.         }
  21.         return getProxy(copy.createAopProxy());
  22.     }
构造proxy对象是有ProxySupport类完成的,他把这个对象委托给了一个AopProxyFactory工厂,而这个理之所有要委托给一个工厂,是因为,生成这个代理类是有选择的:
  1. public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
  2.         if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
  3.             advisedSupport.getProxiedInterfaces().length == 0) {
  4.             if (!cglibAvailable) {
  5.                 throw new AopConfigException(
  6.                         "Cannot proxy target class because CGLIB2 is not available. " +
  7.                         "Add CGLIB to the class path or specify proxy interfaces.");
  8.             }
  9.             return CglibProxyFactory.createCglibProxy(advisedSupport);
  10.         }
  11.         else {
  12.             return new JdkDynamicAopProxy(advisedSupport);
  13.         }
  14.     }
这里生成动态代理类有两种方式,一种是如果用户没有给被代理类实现接口,那么,就会使用cglib来生成代理类,如果制定了实现接口,那么就会使用jdk的InvocationHandler接口实现代理;

这个AopProxy类是一个Proxy Object的包装类;

  1. public interface AopProxy {
  2.     /**
  3.      * Create a new proxy object.
  4.      * <p>Uses the most optimal default class loader (if necessary for proxy creation):
  5.      * usually, the thread context class loader.
  6.      * @see java.lang.Thread#getContextClassLoader()
  7.      */
  8.     Object getProxy();
  9.     /**
  10.      * Create a new proxy object.
  11.      * <p>Uses the given class loader (if necessary for proxy creation).
  12.      * <code>null</code> will simply be passed down and thus lead to the low-level
  13.      * proxy facility's default, which is usually different from the default chosen
  14.      * by the AopProxy implementation's <code>getProxy</code> method.
  15.      * @param classLoader the class loader to create the proxy with
  16.      * (or <code>null</code> for the low-level proxy facility's default)
  17.      */
  18.     Object getProxy(ClassLoader classLoader);
  19. }
能够从中得到代理的Object;

做一个合格的程序猿之浅析Spring AOP源码(十四) 分析ProxyFactoryBean

最基本的实现有三个,AspectJProxyFactory.java ,ProxyFactory.java ProxyFactoryBean这三个,他们的父类ProxyCreatorSupport只是...
  • linuu
  • linuu
  • 2016年03月24日 15:20
  • 3923

BeanFactory 与 FactoryBean的区别及FactoryBean详解

原文地址:http://blog.csdn.net/is_zhoufeng/article/details/38422549 首先要分辨BeanFactory 与 FactoryBean的区...
  • u014604403
  • u014604403
  • 2016年01月14日 10:37
  • 8755

Spring源码分析之ProxyFactoryBean方式实现Aop功能的分析

实现Aop功能有两种方式, 1. ProxyFactoryBean方式: 这种方式是通过配置实现 2. ProxyFactory方式:这种方式是通过编程实现 这里只说ProxyFactoryBean方...
  • u011734144
  • u011734144
  • 2017年06月18日 19:36
  • 1472

Spring中的ProxyFactoryBean

ProxyFactoryBean的作用是产生proxy。 Spring 中 ProxyFactoryBean的层次结构: ProxyFactoryBean的声明如下:public class Prox...
  • gunzh
  • gunzh
  • 2006年01月16日 21:34
  • 6149

Spring BeanNameAutoProxyCreator 与 ProxyFactoryBean区别

一般我们可以使用ProxyBeanFactory,并配置proxyInterfaces,target和interceptorNames实现,但如果需要代理的bean很多,无疑会对spring配置文件的...
  • xyw591238
  • xyw591238
  • 2016年07月22日 15:32
  • 530

Spring源码学习-5.ProxyFactoryBean实现与源代码分析

1.设计原理 proxyConfig 在这个继承关系中,ProxyConfig是最底层的类,这是一个数据基类,为子类提供配置属性 AdvisedSupport: 封装了AOP对通知和通知器的操作 ...
  • bigcaicai1995
  • bigcaicai1995
  • 2015年08月11日 09:08
  • 593

spring aop(五)--ProxyFactoryBean创建代理的实现

先看看ProxyFactoryBean的类层次结构. ProxyFactoryBean实现了FactoryBean,最终通过getObject方法生成Bean,所以getObject方法是个入口...
  • xiejx618
  • xiejx618
  • 2015年02月14日 12:27
  • 2988

spring 直接使用ProxyFactoryBean 实现AOP 流程小结

com\.daodao\.mybatis\..*
  • u011385186
  • u011385186
  • 2017年05月07日 22:26
  • 342

ProxyFactoryBean的几个重要属性

interceptorNames"> target" ref="代理目标类的Bean"> proxyInterfaces"> proxyTargetClass"> proprety的name属性...
  • shadow_ning
  • shadow_ning
  • 2017年01月23日 21:32
  • 422

Spring源代码分析(10)---ProxyFactoryBean(旁敲侧击的AOP时代终于来临)

我们知道,AOP是面向切面编程,在java领域的AOP中,最著名莫过于牛逼哄哄的AspectJ了,我们在前几节的源码分析中,也复习了一下动态代理的知识,在那里,我们采用了几种手段来实现切面效果以及他们...
  • turkeyzhou
  • turkeyzhou
  • 2008年10月02日 14:40
  • 4117
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Spring源代码分析(10)---ProxyFactoryBean(旁敲侧击的AOP时代终于来临)
举报原因:
原因补充:

(最多只允许输入30个字)