zoukankan      html  css  js  c++  java
  • Spring AOP 之编译期织入、装载期织入、运行时织入(转)

    https://blog.csdn.net/wenbingoon/article/details/22888619

    一   前言

                   AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强

           静态代理分为:编译时织入(特殊编译器实现)、类加载时织入(特殊的类加载器实现)。
           动态代理有  :  jdk动态代理(基于接口来实现)、CGlib(基于类实现)。
     
              
         0---aspectj的类加载期织入的实现方式
        

    一 概念理解         

        1     AOP的术语重在理解。

    • Join Point:(连接点) Spring AOP中,join point就是一个方法。(通俗来讲就是起作用的那个方法,具体执行的方法)

    • Pointcut:(切入点)  用来指定join point(通俗来讲就是描述的一组符合某个条件的join point)。通常使用pointcut表达式来限定joint point,Spring默认使用AspectJ pointcut expression language。

    • Advice: 在join point上特定的时刻执行的操作,Advice有几种不同类型,下文将会讨论(通俗地来讲就是起作用的内容和时间点)。

    • Introduction:给对象增加方法或者属性。

    • Target object: Advice起作用的那个对象。

    • AOP proxy: 为实现AOP所生成的代理。在Spring中有两种方式生成代理:JDK代理和CGLIB代理。

    • Aspect: 组合了Pointcut与Advice,在Spring中有时候也称为Advisor。某些资料说Advisor是一种特殊的Aspect,其区别是Advisor只能包含一对pointcut和advice,但是aspect可以包含多对。AOP中的aspect可以类比于OOP中的class。

    • Weaving:将Advice织入join point的这个过程。

    2  Advice的类型

    • Before advice:  执行在join point之前的advice,但是它不能阻止joint point的执行流程,除非抛出了一个异常(exception)。

    • After returning advice: 执行在join point这个方法返回之后的advice。

    • After throwing advice: 执行在join point抛出异常之后的advice。

    • After(finally) advice: 执行在join point返回之后或者抛出异常之后的advice,通常用来释放所使用的资源。

    • Around advice: 执行在join point这个方法执行之前与之后的advice。

    3 两种代理

    Spring AOP是基于代理机制的。上文说到,Spring AOP通过JDK Proxy和CGLIB Proxy两种方法实现代理。

    如果target object没有实现任何接口,那么Spring将使用CGLIB来实现代理。CGLIB是一个开源项目,它是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

    如果target object实现了一个以上的接口,那么Spring将使用JDK Proxy来实现代理,因为Spring默认使用的就是JDK Proxy,并且JDK Proxy是基于接口的。这也是Spring提倡的面向接口编程。当然,你也可以强制使用CGLIB来进行代理,但是这样可能会造成性能上的下降。

       4  Spring对AOP的支持 

    1、如果目标对象实现了接口,默认会采用JDK的动态代理机制实现AOP 
    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 
    3、如果目标对象没有实现接口,必须使用CGLIB生成代理,spring会自动在CGLIB和JDK动态代理之间切换 

    4.如何强制使用CGLIB生成代理? 

    * 添加CGLIB库,SPRING_HOME/lib/cglib/*.jar 

    * 在spring的配置文件中加入: 

    <aop:aspectj-autoproxy proxy-target-class="true"/> 
           <aop:config proxy-target-class="true">
           </aop:config>

       5  当使用@AspectJ自动代理时要强制使用CGLIB,

        请将<aop:aspectj-autoproxy>的proxy-target-class属性设置为true:(组合使用)

    <aop:aspectj-autoproxy proxy-target-class="true"/>

        6   JDK代理和CGLIB代理的区别? 

    * JDK代理只能对实现了接口的类生成代理,而不能针对类 
    * CGLIB是针对类实现代理的,主要对指定的类生成一个子类,并覆盖其中的方法, 
     因为是继承,所以不能使用final来修饰类或方法<aop:aspectj-autoproxy proxy-target-class="true"/> 
    在什么情况下,Spring使用CGLIB做代理? 
    1.在AOP(二)基础上如果将UserManagerImpl.java修改为如下,则Spring会自动使用CGLIB做动态代理; 

    Java代码  收藏代码
    1. package com.wlh.spring;  
    2.   
    3.  //public class UserManagerImpl implements UserManager {  
    4.  public class UserManagerImpl{  
    5.      //目标类不实现接口的情况下,Spring自动使用CGLIB做代理  
    6.     public void addUser(String username, String pwd) {  
    7.       System.out.println("====addUser()=====");  
    8.     }  
    9.   
    10.     public void delUser(int id) {  
    11.          System.out.println("====delUser()=====");  
    12.     }  
    13.   
    14.     public void findUser(int id) {  
    15.          System.out.println("====findUser()=====");  
    16.     }  
    17.   
    18.     public void updateUser(int id, String username, String pwd) {  
    19.          System.out.println("====updateUser()=====");  
    20.     }  
    21.   
    22. }  


    2、如果UserManagerImpl.java类步变,仍然实现了接口UserManager,然后我们在配置文件中,添加一个标签:<aop:aspectj-autoproxy proxy-target-class="true"/> 
    Spring也会使用CGLIB做代理类: 
    <!--<aop:aspectj-autoproxy proxy-target-class="true"/> 支持CGLIB代理 --> 

    <bean id="userManager" class="com.wlh.spring.UserManagerImpl" /> 

    <bean id="securityHandler" class="com.wlh.spring.SecurityHandler" /><!-- 切面类 --> 
    <aop:config> 
    <aop:aspect id="securityAspect" ref="securityHandler"><!-- 引用切面类 --> 
    <!-- 表达式方法声明匹配被切入的类及其方法 --> 
    <aop:pointcut id="applyMethod" 
    expression="execution(* com.wlh.spring.*.add*(..)) || execution(* com.wlh.spring.*.del*(..))" /> 
    <aop:before pointcut-ref="applyMethod" 
    method="checkSecurity" /><!-- 声明切面类的要切入方法 --> 
    </aop:aspect> 
    </aop:config> 

    二   通过静态方法实例化一个bean,实例化出来的bean的类型 对应于静态方法的返回类型,这地点不同于普通的bean

       (1) 静态方法 无参数:

       <bean id="thefmbean" class="springtest.FactoryMethodBean" factory-method="getInstance" />

       (2) 静态方法有一个参数

       <bean id="thenamedfmbean" class="springtest.FactoryMethodBean" 
             factory-method="getNamedInstance">
            <constructor-arg value="China" />
      </bean>
          这里<constructor-arg value="China" />表示为静态方法参数的值

      (3) 对于(2)实例化出来的bean,再进行属性set

       <bean id="thenamedfmbean" class="springtest.FactoryMethodBean" 
             factory-method="getNamedInstance">
            <constructor-arg value="China" />
            <property name="id" value="20" />
      </bean>

     (4). 对一个已经实例化的bean,得到其普通方法返回的对象,参数方式与1完全相同

      <bean id="duke" class="springtest.Juggler">
        <constructor-arg value="15" />
      </bean>
        <constructor-arg value="Mike" />
        <property name="id" value="18" />
      </bean>

    三  基于XML的spring AOP配置

       AOP(Aspect-Oriented Programming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

      <bean id="employee" factory-bean="duke" factory-method="getYourEmployee">

         而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即切面。所谓“切面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向切面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“切面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

          使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

     

          实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“切面”,从而使得编译器可以在编译期间织入有关“切面”的代码。然而殊途同归,实现AOP的技术特性却是相同的,分别为:

          1、join point(连接点):是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个join point。
          2、point cut(切入点):本质上是一个捕获连接点的结构。在AOP中,可以定义一个point cut,来捕获相关方法的调用。

          3、advice(通知):是point cut的执行代码,是执行“切面”的具体逻辑。
          4、aspect(切面):point cut和advice结合起来就是aspect,它类似于OOP中定义的一个类,但它代表的更多是对象间横向的关系。
          5、introduce(引入):为对象引入附加的方法或属性,从而达到修改对象结构的目的。有的AOP工具又将其称为mixin。

          6、AOP代理(AOP Proxy):AOP框架创建的对象,这个对象通常可以作为目标对象的替代品,而AOP代理提供比目标对象更加强大的功能。真实的情形是,当应用调用AOP代理的方法时,AOP代理会在自己的方法中回调目标对象的方法,从而完成应用的调用。关于AOP代理的典型例子就是Spring中的事务代理Bean。通常,目标Bean的方法不是事务性的,而AOP代理包含目标Bean的全部方法,而且这 些方法经过加强变成了事务性方法。简单地说,目标对象是蓝本,AOP代理是目标对象的加强,在目标对象的基础上,增加属性和方法,提供更强大的功能。
    目标对象包含一系列切入点。切入点可以触发处理连接点集合。用户可以自己定义切入点,如使用正则表达式。AOP代理包装目标对象,在切入点处加入处理。在切入点加入的处理,使得目标对象的方法功能更强。Spring 默认使用JDK动态代理实现AOP代理,主要用于代理接口。也可以使用CGLIB代理。实现类的代理,而不是接口。如果业务对象没有实现接口,默认使用 CGLIB代理。但面向接口编程是良好的习惯,尽量不要面向具体类编程。因此,业务对象通常应实现一个或多个接口。

          7、目标对象(Target Object):包含一个连接点的对象,也被称为代理对象。

          8、 前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在<aop:aspect>里面使用<aop:before>元素进行声明。 

          9、后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在<aop:aspect>里面使用<aop:after>元素进行声明。

          10、返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext中在<aop:aspect>里面使用<after-returning>元素进行声明。 

          11、环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在<aop:aspect>里面使用<aop:around>元素进行声明。

          12、抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。

         Spring2.0目前只支持使用方法调用作为连接点(join point)。

         Spring 定义切入点语法:excution(modifiers-pattern?ret-type-pattern declaring-type-pattern ?name-pattern(param-pattern)throws-pattern?)

          除了ret-type-pattern (即返回类型模式)、name-pattern(param-pattern)(名字模式和参数模式)外,其他模式都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点(即一个方法)。使用最频繁的一个返回类型模式是*,它代表了匹配任意的返回类型。如果写明了返回类型,比如String,那么只能匹配返回String类型的连接点(方法)。名字模式匹配的是方法名。你可以用*通配符表示匹配所有方法名。参数模式中,()表示匹配了不接受任何参数的方法,而(。。)表示匹配任意数量参数的方法。模式(*)表示匹配任意类型参数的方法。模式(*,String)表示匹配:第一个为任意参数类型,第二个必须为String类型的方法。

           modifiers-pattern:方法的操作权限

           ret-type-pattern:返回值

           declaring-type-pattern:方法所在的包

           name-pattern:方法名

            parm-pattern:参数名

           throws-pattern:异常

          下面是定义切入点的例子:

           。任意公共方法的执行:

              excution(public * *(。。))

           。任何一个以set开头的方法执行:

              excution(* set*(。。))

           。AccountService接口的任意方法的执行:

              excution(* com.xyz.service.AccountService.*(。。))

           。定义在service包的任意方法的执行:

              excution(* com.xyz.service.*.*(。。))

           。定义在service包或子包的任意方法的执行:

               excution(* com.xyz.service..*.*(。。))

    -----------------------------------------------------华丽的分隔线----------------------------------------------

     

            在Spring配置文件里,所有的切面和通知器都要配置在<aop:config>标签里,一个applicationContext可以包含多个<aop:config>,一个<aop:config>可以包含pointcut、advisor、aspect元素(注意必须是这个顺序)。

            1、声明一个切面

             <aop:config>

                  <aop:aspect id="myAspect" ref="myBean">

                       。。。。。

                  </aop:aspect>

             </aop:config>

             <bean id="myBean" class="">

                  。。。。。

              </Bean>

             说明:切面用<aop:aspect>来声明,backing bean(支持bean)用ref引用。

             2、声明一个切入点

             <aop:config>

                   <aop:pointcut id="myPointcut" expression="excution(* com.service.*.*(..))"/>

             </aop:config>

             3、声明一个通知

               Spring2.0通过<aop:advisors>元素来支持advisors概念,大多数情况下,它将和transaction advice一起使用,格式如下:

               <aop:config>

                    <aop:pointcut id="myService" expression="excution(* com.xyz.service.*.*(..))"/>

                    <aop:advisors pointcut-ref="myService" advice-ref="tx-advice"/>

               </aop:config>

              <txt:advice id="tx-advice">

                    <tx:attributes>

                          <tx:method name="inser*" propagation="REQUIRED" rollback-for="Exception"/>
                          <tx:method name="updat*" propagation="REQUIRED" rollback-for="Exception" />
                          <tx:method name="delet*" propagation="REQUIRED" rollback-for="Exception" />
                          <tx:method name="process*" propagation="REQUIRED" rollback-for="Exception" />
                          <tx:method name="*" propagation="SUPPORTS" read-only="true"/>

                    </tx:attributes>

               </txt:advice>  

               说明:advisors 执行切入点方法时都要执行advice-ref引用的事务处理

    四  <aop:aspectj-autoproxy />  与<aop:config proxy-target-class="true">的作用

     

    4.1  <aop:aspectj-autoproxy />

          通过配置织入@Aspectj切面

    虽然可以通过编程的方式织入切面,但是一般情况下,我们还是使用spring的配置自动完成创建代理织入切面的工作。

     

    通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring

    在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了

     

    <aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强;


    当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强;


    不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

     

     

     4.2 <aop:config proxy-target-class="true">

    Spring AOP使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议优先使用JDK的动态代理)

        1  如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。 

        2  若该目标对象没有实现任何接口,则创建一个CGLIB代理。

        3  如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法) 那也可以。但是需要考虑以下问题: 

    • 无法通知(advise)final方法,因为他们不能被覆写。

    • 代理对象的构造器会被调用两次。因为在CGLIB代理模式下每一个代理对象都会 产生一个子类。每一个代理实例会生成两个对象:实际代理对象和它的一个实现了通知的子类实例 而是用JDK代理时不会出现这样的行为。通常情况下,调用代理类型的构造器两次并不是问题, 因为除了会发生指派外没有任何真正的逻辑被实现。
    • 且CGLib的效率没有使用JDK代理机制高,速度平均要慢8倍左右。
    强制使用CGLIB代理需要将<aop:config>的proxy-target-class属性设为true:
    1 <aop:config proxy-target-class="true">
    2    ...
    3 </aop:config>

    当使用@AspectJ自动代理时要强制使用CGLIB,请将<aop:aspectj-autoproxy>的proxy-target-class属性设置为true:(组合使用)

    <aop:aspectj-autoproxy proxy-target-class="true"/>

     

    五 Spring常用注解,自动扫描装配Bean

     

    spring自动扫描机制

    spring2.5为我们引入了组件自动扫描机制,它可以在classPath路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。

    也就是要spring自动扫描机制只会查找指定类路径下包含@Component、@Service、@Controller、@Repository这四种注解的类。

    要使用自动扫描机制,我们需要打开以下配置信息:

    1、引入context命名空间 需要在xml配置文件中配置以下信息: 同上先引入context 命名空间,同时

    2、在配置文件中添加context:component-scan标签

    <context:component-scan base-package="*"/> 

    其中base-package为需要扫描的包(含子包)。

    注:

    1、在使用组件扫描元素时,AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor会隐式地被包括进来。 也就是说,连个组件都会被自动检测并织入 - 所有这一切都不需要在XML中提供任何bean配置元数据。也就是说如果使用了context:component-scan标签,就可以不需要再引入context:annotation-config标签

    <context:component-scan />还允许定义过滤器将基包下的某些类纳入或排除。Spring支持以下4种类型的过滤方式:
    过滤器类型 表达式范例 说明 
    注解 org.example.SomeAnnotation 将所有使用SomeAnnotation注解的类过滤出来 
    类名指定 org.example.SomeClass 过滤指定的类 
    正则表达式 com.kedacom.spring.annotation.web..* 通过正则表达式过滤一些类 
    AspectJ表达式 org.example..*Service+ 通过AspectJ表达式过滤一些类 

    以正则表达式为例,我列举一个应用实例:

    Java代码 
    <context:component-scan base-package="com.casheen.spring.annotation"> 
        <context:exclude-filter type="regex" expression="com.casheen.spring.annotation.web..*" />
    </context:component-scan> 

            <context:component-scan base-package="com.casheen.spring.annotation">
                    <context:exclude-filter type="regex" expression="com.casheen.spring.annotation.web..*" />
            </context:component-scan>

    值得注意的是<context:component-scan />配置项不但启用了对类包进行扫描以实施注释驱动Bean定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor),因此当使用<context:component-scan />后,就可以将<context:annotation-config />移除了。


    六   常用注解

     

    --定义Bean的注解

     

    @Controller

    @Controller("Bean的名称")

    定义控制层Bean,如Action

     

    @Service          

    @Service("Bean的名称")

    定义业务层Bean

     

    @Repository   

    @Repository("Bean的名称")

    定义DAO层Bean

     

    @Component  

    定义Bean, 不好归类时使用.

     

    --自动装配Bean (选用一种注解就可以)

    @Autowired  (Srping提供的)

    默认按类型匹配,自动装配(Srping提供的),可以写在成员属性上,或写在setter方法上

     

    @Autowired(required=true)  

    一定要找到匹配的Bean,否则抛异常。 默认值就是true 

     

    @Autowired

    @Qualifier("bean的名字") 

    按名称装配Bean,与@Autowired组合使用,解决按类型匹配找到多个Bean问题。

     

    @Resource   JSR-250提供的

    默认按名称装配,当找不到名称匹配的bean再按类型装配.

    可以写在成员属性上,或写在setter方法上

    可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是未指定name属性, 默认使用成员属性的变量名,一般不用写name属性.

    @Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.

     

    @Inject   是JSR-330提供的

    按类型装配,功能比@Autowired少,没有使用的必要。

     

    --定义Bean的作用域和生命过程

    @Scope("prototype")

    值有:singleton,prototype,session,request,session,globalSession

     

    @PostConstruct 

    相当于init-method,使用在方法上,当Bean初始化时执行。

     

    @PreDestroy 

    相当于destory-method,使用在方法上,当Bean销毁时执行。

     

    --声明式事务

    @Transactional

    六   配置工厂Bean 

             通常由应用程序直接使用new创建新对象,为了将对象的创建与使用相分离,采用工厂模式,即应用程序将对象的创建与初始化交给工厂来完成。
           一般情况下,应用程序有自己的工厂对象来创建bean,如果将工厂对象交给Springle管理,那么Spring管理的就不是普通的bean,而是工厂Bean。调用getBean()方法,Spring返回的不是直接创建的Bean的实例,而是由工厂创建的Bean实例。


    一般在Spring中配置工廠Bean,有3中不同類型的工廠Bean的配置. 

    1.静态工厂 創建具體Bean實例的是靜態方法 


    1. import java.util.Random;   
    2. public class Static FactoryBean{   
    3. public static  
    4. Integer createRandom() {   
    5. return new  
    6. Integer(new Random().nextInt());  
    7. }  
    8. }   
        將其納入Spring容器來管理,需要通過factory-method指定静态方法名称,方法必须是static的,才能找到。
    1.   
    1. <bean id="random"  
    2. class="example.chapter3.StaticFactoryBean"  
    3. factory-method="createRandom"//createRandom方法必須是static的,才能找到  
    4. scope="prototype"  
    5. />   


    測試: 
    1. public static void main(String[] args) {  
    2. XmlBeanFactory factory = new XmlBeanFactory(new  
    3. ClassPathResource("config.xml"));  
    4. System.out.println(factory.getBean("random").toString());   
    5. //StaticFactoryBean sfb =  
    6. (StaticFactoryBean)factory.getBean("random");  
    7. //System.out.println(sfb.createRandom().toString());   
    8.   
    9. //調用getBean()時,返回隨機數.如果沒有指定factory-method,會返回StaticFactoryBean的實例,即返回工廠Bean的實例  
    10. }   

    2.实例工厂  創建具體Bean實例的是實例,不是靜態方法 

    1. import java.text.SimpleDateFormat;  
    2. import java.util.Date;   
    3. public class InstanceFactoryBean {   
    4. private String format = "yy-MM-dd HH:mm:ss";   
    5. public void setFormat(String format) {  
    6. this.format = format;  
    7. public String createTime() {  
    8. return new SimpleDateFormat(format).format(new Date());  
    9. }  
    10. }  


     配置文件需要配置兩個bean:第一個Bean和普通的Bean沒有區別,第二個bean定義如何通過工廠Bean獲取Bean,需要指定工廠Bean的名稱和方法名稱 
     
    1. <bean id="instanceFactoryBean" class="example.chapter3.InstanceFactoryBean">  
    2.      <property name="format" value="yyyy-MM-dd HH:mm:ss"/>  
    3. </bean>   
    4. <bean id="currentTime" factory-bean="instanceFactoryBean" factory-method="createTime"/>   
     
    測試: 
    1. public static void main(String[] args) {  
    2. XmlBeanFactory factory = new XmlBeanFactory(new  
    3. ClassPathResource("config.xml"));  
    4. System.out.println(factory.getBean("currentTime"));  
    5. }   

    3.實現FactoryBean接口 

    1. public class PiFactoryBean implements FactoryBean {   
    2. public Object getObject() throws Exception {  
    3. return new Double(3.14159265358979);  
    4. public Class getObjectType() {  
    5. return Double.class;  
    6. public boolean isSingleton() {  
    7. return true;  
    8. } }   
    實現了FactoryBean接口的Bean,不再被視爲普通的Bean.Spring會自動檢測. 

    1. <bean id="pi"class="example.chapter3.PiFactoryBean"/>  
     
     測試 
    1. public static void main(String[] args) throws Exception {  
    2. XmlBeanFactory factory = new XmlBeanFactory(new  
    3. ClassPathResource("config.xml"));  
    4. System.out.println(factory.getBean("pi"));//返回PiFactoryBean  
    5. 的工廠方法getObject返回的Double對象實例  
    6. //PiFactoryBean p =  
    7. (PiFactoryBean)factory.getBean("&pi");  
    8. //加"&"返回工廠Bean的實例.  
    9. //System.out.println(p.getObject());  
    10. }  

    参考:
         
          http://log-cd.iteye.com/blog/562056   使用AspectJ LTW(Load Time Weaving)--aop总体理解
          http://blog.csdn.net/hannover100/article/details/7882893
          http://tc.chinawin.net/it/softwaredev/article-24a4f.html
          http://www.cnblogs.com/yangy608/archive/2010/11/14/1876839.html

  • 相关阅读:
    打造基于CentOS7的xfce最简工作环境
    Linux下C程序的编辑,编译和运行以及调试
    修正 XE6 TListView 上方 SearchBok 右边的清除钮显示
    TabControl 显示彩色的图示 (XE6 Firemonkey)
    TSwitch 中文简繁显示支持(XE6 Android)
    改变 TMemo 的背景颜色 (Firemonkey)
    修正 XE5 Android 键盘三个问题
    Delphi 收藏
    展示 Popup 的使用方法
    ListView 下拉更新 (支持 Android)
  • 原文地址:https://www.cnblogs.com/devilwind/p/8862043.html
Copyright © 2011-2022 走看看