CSDN博客

img turkeyzhou

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

发表于2008/10/2 14:40:00  3993人阅读

我们知道,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;

0 0

相关博文

我的热门文章

img
取 消
img