• 由代理模式到AOP的实例分析


    内容来自书籍《架构探险-从零开始写Java Web框架》的整理

    代理模式

    首先看什么是代理?

    代理的英文单词是Proxy,意思是不用你自己去做某件事,而是指派一位代理去帮你做,完成的效果和你自己做是一样的!比如单就上班打卡来说,你自己打卡和别人帮你打卡,对于打卡任务来说,结果是一样的!

    代理有下面几种:

    1.静态代理

    代码综述:

    一个业务接口,

    一个业务接口的实现类,

    一个代理类,

    一个测试类

    业务接口类(这个是后面实例要实现的一个公共接口):

    1 package com.hm;
    2 /**实际的主要的业务接口*/
    3 public interface IHello {
    4     void sayHello();
    5 }

    业务接口实现类(这个是后面实例要代理的一个公共业务实现类,并且后续会有改动)

    1 package com.hm;
    2 import org.springframework.stereotype.Component;
    3 /**实际的实现了业务接口的实现类,也是将要被代理的目标类*/
    4 public class HelloImpl implements IHello{
    5     @Override
    6     public void sayHello() {
    7         System.out.println("hello in helloImpl");
    8     }
    9 }

    业务实现类的静态代理类

     1 package com.hm.staticproxy;
     2 import com.hm.HelloImpl;
     3 import com.hm.IHello;
     4 /**
     5  * 这是一个代理类,但是都这样代理的话,代理类会越来越多
     6  */
     7 public class HelloProxy implements IHello{
     8 
     9     private HelloImpl helloImpl;
    10     
    11     public HelloProxy(){
    12         this.helloImpl = new HelloImpl();
    13     }
    14     
    15     @Override
    16     public void sayHello() {
    17         before();
    18         this.helloImpl.sayHello();
    19         after();
    20     }
    21     
    22     public void before(){
    23         System.out.println("before in helloProxy");
    24     }
    25     
    26     public void after(){
    27         System.out.println("after in helloProxy");
    28     }
    29 }

    测试类(没有使用Junit):

    1 package com.hm.staticproxy;
    2 public class Test1 {
    3     public static void main(String[] args) {
    4         HelloProxy hp = new HelloProxy();
    5         hp.sayHello();
    6     }
    7 }

    可以看出静态代理类HelloProxy实现了和业务实现类HelloImpl实现了相同的接口IHello,在使用时,直接使用代理类就可以调用到实际的业务实现方法sayHello(),但是缺点也很明显,随着实现类变多,静态代理类也会随之变多,从而变成“类爆炸”。

    2.JDK动态代理

    使用JDK动态代理类会解决上述类爆炸的问题,只需要实现一个InvocationHandler接口就可以由JDK来生成你自己的代理类,比较方便。

    JDK的动态代理类:

     1 package com.hm.dynamicproxy;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.lang.reflect.Proxy;
     6 /**
     7  * JDK的动态代理类只有一个,一个类即完成了各种代理任务
     8  * 但是被代理类必须实现某个接口才行
     9  * @author Administrator
    10  */
    11 public class DynamicProxy implements InvocationHandler{
    12 
    13     private Object target;
    14     
    15     public DynamicProxy(Object target){
    16         this.target = target;
    17     }
    18     
    19     @Override
    20     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    21         before();
    22         Object result = method.invoke(target, args);
    23         after();
    24         return result;
    25     }
    26 
    27     /**
    28      * 这个是为了方便特意优化的一点
    29      * 并且使用了泛型,不用每次强制转型
    30      * 由这个方法的参数this.target.getClass().getInterfaces()可以看出
    31      * 使用JDK的动态代理,被代理类必须实现最少一个接口
    32      * 否则 无法实现代理,这时候需要使用CGLib
    33      * @return
    34      */
    35     @SuppressWarnings("unchecked")
    36     public <T> T getProxy(){
    37         T t = (T) Proxy.newProxyInstance(
    38                 this.target.getClass().getClassLoader(), 
    39                 this.target.getClass().getInterfaces(), 
    40                 this);
    41         return t;
    42         
    43     }
    44     
    45     public void before(){
    46         System.out.println("before in DynamicProxy");
    47     }
    48     
    49     public void after(){
    50         System.out.println("after in DynamicProxy");
    51     }
    52 }

    测试类如下:

     1 package com.hm.dynamicproxy;
     2 
     3 import java.lang.reflect.Proxy;
     4 import com.hm.HelloImpl;
     5 import com.hm.IHello;
     6 
     7 public class Test2 {
     8     
     9     public static void main(String[] args) {
    10         Test2 t2 = new Test2();
    11         t2.test1();
    12         System.out.println("----------------------------");
    13         t2.test2();
    14     }
    15     
    16     //这个是直接使用动态代理的方式,不过每次使用都要重复写出newInstance的过程,可以优化
    17     public void test1(){
    18         IHello hello = new HelloImpl();
    19         DynamicProxy dp = new DynamicProxy(hello);
    20         //需要强制转型
    21         IHello helloProxy = (IHello) Proxy.newProxyInstance(
    22                 hello.getClass().getClassLoader(), 
    23                 hello.getClass().getInterfaces(), 
    24                 dp);
    25         helloProxy.sayHello();
    26     }
    27     
    28     //这个也是直接使用动态代理的方式,不过生成代理的代码进行了优化
    29     public void test2(){
    30         IHello helloProxy = new DynamicProxy(new HelloImpl()).getProxy();
    31         helloProxy.sayHello();
    32     }
    33 }

    这样JDK动态代理类也实现了,并且只有一个代理类,很方便。但是,由这句代码

    Proxy.newProxyInstance(

                this.target.getClass().getClassLoader(),

                this.target.getClass().getInterfaces(),

                this)

    可以看出,第二个参数是返回业务类的父接口。那如果该业务类没有实现任何接口,JDK代理就无法使用了!

    3.CGLib动态代理

    Cglib是一个开源类库,这里使用它的话需要引入cglib.jar,可以自行下载

     1 package com.hm.cglibproxy;
     2 
     3 import java.lang.reflect.Method;
     4 
     5 import net.sf.cglib.proxy.Enhancer;
     6 import net.sf.cglib.proxy.MethodInterceptor;
     7 import net.sf.cglib.proxy.MethodProxy;
     8 /**
     9  * CGLib的代理不要求被代理类必须实现某接口,它是方法级别 的代理(拦截)
    10  * @author Administrator
    11  *
    12  */
    13 public class CGLibProxy implements MethodInterceptor{
    14 
    15     private static CGLibProxy instance;
    16 
    17     public static CGLibProxy getInstance(){
    18         if(instance == null){
    19             instance = new CGLibProxy();
    20         }
    21         return instance;
    22     }
    23     
    24     @Override
    25     public Object intercept(Object obj, Method method, Object[] args,
    26             MethodProxy proxy) throws Throwable {
    27         before();
    28         Object result = proxy.invokeSuper(obj, args);
    29         after();
    30         return null;
    31     }
    32     
    33     public <T> T getProxy(Class<T> clazz){
    34         return (T) Enhancer.create(clazz, this);
    35     }
    36     
    37     public void before(){
    38         System.out.println("before in CGLibProxy");
    39     }
    40     
    41     public void after(){
    42         System.out.println("after in CGLibProxy");
    43     }
    44 }

    测试类如下:

     1 package com.hm.cglibproxy;
     2 
     3 import com.hm.HelloImpl;
     4 import com.hm.IHello;
     5 
     6 public class Test3 {
     7 
     8     public static void main(String[] args) {
     9         test1();
    10         System.out.println("--------------------------------");
    11         test2();
    12     }
    13     
    14     public static void test1(){
    15         CGLibProxy cp = new CGLibProxy();
    16         IHello helloProxy = cp.getProxy(HelloImpl.class);
    17         helloProxy.sayHello();
    18     }
    19     public static void test2(){
    20         IHello helloProxy = CGLibProxy.getInstance().getProxy(HelloImpl.class);
    21         helloProxy.sayHello();
    22     }
    23     
    24 }

    至此三种代理的简单实现就讲完了!

    Spring AOP

    下面就来看看AOP吧

    AOP面向切面编程,横切逻辑…等等就不多说了

    这里主要分为:前置增强,后置增强,环绕增强,异常抛出增强

    需要引入spring的jar包,我这里使用的是3.2版本

    Jar如下:

     

    为了方便我直接把spring3.2的所有jar包都引入了

    还是来实现之前的业务接口IHello,代理之前的实现类HelloImpl吧

    编程式:

    前置增强

    代码如下:

     1 package com.hm.spring;
     2 
     3 import java.lang.reflect.Method;
     4 import org.springframework.aop.MethodBeforeAdvice;
     5 /**
     6  * 前置增强
     7  * @author Administrator
     8  */
     9 public class HelloBeforeAdvice implements MethodBeforeAdvice {
    10     @Override
    11     public void before(Method arg0, Object[] arg1, Object arg2)
    12             throws Throwable {
    13         System.out.println("Before in HelloBeforeAdvice");
    14     }
    15 }

    后置增强

     1 package com.hm.spring;
     2 
     3 import java.lang.reflect.Method;
     4 import org.springframework.aop.AfterReturningAdvice;
     5 /**
     6  * 后置增强
     7  * @author Administrator
     8  */
     9 public class HelloAfterAdvice implements AfterReturningAdvice{
    10 
    11     @Override
    12     public void afterReturning(Object arg0, Method arg1, Object[] arg2,
    13             Object arg3) throws Throwable {
    14         System.out.println("After in HelloAfterAdvice");
    15     }
    16 }

    测试类如下

    (这个是后面spring的公共测试类,后面会改动,注意文件名)

     1 package com.hm.spring;
     2 
     3 import org.springframework.aop.framework.ProxyFactory;
     4 import com.hm.HelloImpl;
     5 import com.hm.IHello;
     6 
     7 public class ClientTest {
     8     public static void main(String[] args) {
     9         test1();
    10         System.out.println("------------------");
    11         test2();
    12     }
    13     
    14     /**
    15      * 前置增强
    16      */
    17     static void test1(){
    18         //创建代理工厂
    19         ProxyFactory pf = new ProxyFactory();
    20         //射入目标类对象
    21         pf.setTarget(new HelloImpl());
    22         //添加前置增强
    23         pf.addAdvice(new HelloBeforeAdvice());
    24         //添加后置增强
    25         pf.addAdvice(new HelloAfterAdvice());
    26         //从方法中获取代理
    27         IHello hello = (IHello) pf.getProxy();
    28         //调用代理的方法
    29         hello.sayHello();    
    30 }
    31     /**
    32      * 后置增强
    33      */
    34     static void test2(){
    35         ProxyFactory pf = new ProxyFactory();
    36         pf.setTarget(new HelloImpl());
    37         pf.addAdvice(new HelloBeforeAfterAdvice());
    38         
    39         IHello hello = (IHello) pf.getProxy();
    40         hello.sayHello();
    41     }
    42 }

    运行结果如下:

    Before in HelloBeforeAdvice

    hello in helloImpl

    After in HelloAfterAdvice

    ------------------

    before in HelloBeforeAfterAdvice

    hello in helloImpl

    after in HelloBeforeAfterAdvice

     

    环绕增强

    也可以定义一个增强类,同时实现这两个接口,这就形成了环绕增强

     1 package com.hm.spring;
     2 
     3 import java.lang.reflect.Method;
     4 import org.springframework.aop.AfterReturningAdvice;
     5 import org.springframework.aop.MethodBeforeAdvice;
     6 
     7 /**
     8  * 实现两个接口,共同完成环绕增强
     9  * @author Administrator
    10  */
    11 public class HelloBeforeAfterAdvice implements     MethodBeforeAdvice,AfterReturningAdvice{
    12 
    13     @Override
    14     public void before(Method arg0, Object[] arg1, Object arg2)
    15             throws Throwable {
    16         System.out.println("before in HelloBeforeAfterAdvice");    
    17     }
    18     
    19     @Override
    20     public void afterReturning(Object arg0, Method arg1, Object[] arg2,
    21             Object arg3) throws Throwable {
    22         System.out.println("after in HelloBeforeAfterAdvice");    
    23     }
    24 }

    同时也可以直接实现MethodInterceptor接口从而实现环绕增强,该接口不是spring提供的,而是AOP联盟写的,spring只是借用了它,故需要引入aopalliance.jar

    如下:

     1 package com.hm.spring;
     2 
     3 import org.aopalliance.intercept.MethodInterceptor;
     4 import org.aopalliance.intercept.MethodInvocation;
     5 /**
     6  * 环绕增强
     7  * @author Administrator
     8  *
     9  */
    10 public class HelloAroundAdvice implements MethodInterceptor{
    11 
    12     @Override
    13     public Object invoke(MethodInvocation invocation) throws Throwable {
    14         before();
    15         Object result = invocation.proceed();
    16         after();
    17         return result;
    18     }
    19     
    20     private void before(){
    21         System.out.println("before in HelloAroundAdvice");
    22     }
    23     private void after(){
    24         System.out.println("after in HelloAroundAdvice");
    25     }
    26 }

    声明式

    先提供一个spring的配置文件,beans.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3     xmlns:aop="http://www.springframework.org/schema/aop" 
     4     xmlns:context="http://www.springframework.org/schema/context"
     5     xmlns:p="http://www.springframework.org/schema/p"
     6     xmlns:tx="http://www.springframework.org/schema/tx" 
     7     xmlns:util="http://www.springframework.org/schema/util"
     8     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
     9         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd  
    10         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd  
    11         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd  
    12         http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
    13 
    14     <!-- 自动包扫描 -->
    15 <context:component-scan base-package="com.hm" />
    16     
    17     <bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    18         <!-- 需要代理的接口 ,注意是value-->
    19         <property name="interfaces" value="com.hm.IHello"/>
    20         <!-- 接口的实现类(目标类),注意是ref,指向一个bean -->
    21         <property name="target" ref="HelloImpl"/>
    22         <!-- 拦截器名称,即增强类的名称,spring bean的id -->
    23         <property name="interceptorNames">
    24             <list>
    25                 <value>HelloAroundAdvice</value>
    26 <value>HelloAfterAdvice</value>
    27 <value>HelloBeforeAdvice</value>
    28             </list>
    29         </property>
    30         <!--仅一个增强类时可以像如下配置--> 
    31         <!--
    32         <property name="interceptorNames" value="HelloAroundAdvice"/>
    33          -->
    34     </bean>
    35 </beans>

    主要注意的地方有:

    1:

    1         <!-- 接口的实现类(目标类),注意是ref,指向一个bean -->
    2         <property name="target" ref="HelloImpl"/>

    这里使用的是ref配置,所以HelloImpl是一个bean的名字,由于使用声明式配置,所以需要在公共业务实现类HelloImpl.java中添加一个注解,如下:

    1 ……
    2 @Component("HelloImpl")
    3 public class HelloImpl implements IHello{
    4 ……

    2:

    1         <!-- 拦截器名称,即增强类的名称,spring bean的id -->
    2         <property name="interceptorNames">

    这里同样是bean的名字,故需要在这上个增强类上添加注解:

    1 @Component("HelloBeforeAdvice")
    2 public class HelloBeforeAdvice implements MethodBeforeAdvice {
    3 
    4 
    5 @Component("HelloAfterAdvice")
    6 public class HelloAfterAdvice implements AfterReturningAdvice{
    7 
    8 @Component("HelloAroundAdvice")
    9 public class HelloAroundAdvice implements MethodInterceptor{

    这样在公共测试类ClientTest.java里面添加两个方法:

     1     /**
     2      * 环绕增强
     3      * 编程式
     4      */
     5     static void test3(){
     6         ProxyFactory pf = new ProxyFactory();
     7         pf.setTarget(new HelloImpl());
     8         pf.addAdvice(new HelloAroundAdvice());
     9         
    10         IHello hello = (IHello) pf.getProxy();
    11         hello.sayHello();
    12     }
    13     
    14     /**
    15      * 测试annotation版本的环绕增强
    16      * 声明式
    17      */
    18     static void test4(){
    19         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    20         IHello hello = (IHello) context.getBean("helloProxy");
    21         hello.sayHello();
    22     }

    然后在main方法里面执行,结果如下:

    before in HelloAroundAdvice

    Before in HelloBeforeAdvice

    hello in helloImpl

    After in HelloAfterAdvice

    after in HelloAroundAdvice

    可以看出相比前置和后置增强,环绕增强的结果在更前更后的位置

    异常抛出增强

    代码如下:

     1 package com.hm.spring;
     2 
     3 import java.lang.reflect.Method;
     4 import org.springframework.aop.ThrowsAdvice;
     5 import org.springframework.stereotype.Component;
     6 
     7 /**
     8  * 异常抛出增强
     9  * @author Administrator
    10  *
    11  */
    12 @Component("HelloThrowAdvice")
    13 public class HelloThrowAdvice implements ThrowsAdvice{
    14     
    15     public void afterThrowing(Method method,Object[] args,Object target,Exception e){
    16         System.out.println("-------Throw Exception------");
    17         System.out.println("Target Class: " + target.getClass().getName());
    18         System.out.println("Method Name: " + method.getName());
    19         System.out.println("Exception Message: " + e.getMessage());
    20         System.out.println("---------------------------");
    21     }
    22 }

    直接在beans.xml中配置该bean:

    1 <bean id="helloThrowProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    2         <property name="interfaces" value="com.hm.IHello"/>
    3         <property name="target" ref="HelloThrowsImpl"/>
    4         <property name="interceptorNames" value="HelloThrowAdvice"/>
    5     </bean>

    在测试方法ClientTest.java中添加测试方法:

    1 /**
    2      * 测试异常抛出增强
    3      */
    4     static void test5(){
    5         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    6         IHello hello = (IHello) context.getBean("helloThrowProxy");
    7         hello.sayHello();
    8     }

    在main方法中测试如下:

    正是我们抛出的异常,已经被拦截(捕获,增强),拿到这些异常信息,则可以将其写到日志,持久化到数据库中。

    引入增强

    如果某个类实现了接口A,但是没有实现接口B,那么该类是否可以调用B中的方法呢?

    通过引入增强则可以做到(只能说厉害)

    首先在加入另外一个接口IApology

     1 package com.hm;
     2 
     3 /**
     4  * 不相关的接口
     5  * HelloImpl没有实现该接口,但是在ClientTest#test6()中却可以看到这样的调用
     6  * IApology apology = (IApology) helloImpl;
     7  * apology.saySorry();
     8  * 将HelloImpl转型为IApology即可以调用
     9  * @author Administrator
    10  *
    11  */
    12 public interface IApology {
    13 
    14     void saySorry();
    15 }

    可以看到业务实现类HelloImpl并没有实现IApology接口,但是却想在程序运行的时候动态实现它,同时,如果HelloImpl业务很复杂,代码很多,并不想改动它的代码。怎么做呢?

    借助一个spring的引入增强:

     1 package com.hm.spring;
     2 
     3 import org.aopalliance.intercept.MethodInvocation;
     4 import org.springframework.aop.support.DelegatingIntroductionInterceptor;
     5 import org.springframework.stereotype.Component;
     6 import com.hm.IApology;
     7 
     8 /**
     9  * 简述:
    10  * 某个类实现了A接口,但是没有实现B接口,那么该类是否可以调用B接口的方法呢?
    11  * 使用下面的代理即可
    12  * 这是对类的增强-Introduction Advice
    13  * @author Administrator
    14  *
    15  */
    16 @Component("HelloIntroAdvice")
    17 public class HelloIntroAdvice extends DelegatingIntroductionInterceptor implements IApology{
    18 
    19     public Object invoke(MethodInvocation invocation) throws Throwable{
    20         return super.invoke(invocation);
    21     }
    22     
    23     @Override
    24     public void saySorry() {
    25         System.out.println("sorry in HelloIntroAdvice");
    26     }
    27 }

    在beans.xml中配置该bean:

    1 <bean id="helloIntroProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    2         <property name="interfaces" value="com.hm.IApology"/>
    3         <property name="target" ref="HelloImpl"/>
    4         <property name="interceptorNames" value="HelloIntroAdvice"/>
    5         <!-- 代理目标的类:true表示spring用CGLib做代理,false表示用JDK的动态代理 -->
    6         <property name="proxyTargetClass" value="true"/>
    7     </bean>

    在ClientTest中添加测试方法:

     1     /**
     2      * 测试织入增强
     3      */
     4     static void test6(){
     5         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
     6         //这里转为目标类,而不是它的接口类
     7         HelloImpl helloImpl = (HelloImpl) context.getBean("helloIntroProxy");
     8         helloImpl.sayHello();
     9         //将目标类强制 向上转型为IApology接口--"接口动态代理"
    10         IApology apology = (IApology) helloImpl;
    11         apology.saySorry();
    12     }

    在main方法中执行如下:

     

    可以看到,最终通过强制类型转换实现了由helloImpl到apology的转化,从而调用到了saySorry()方法,真腻害!

    测试拦截方法的数量:

    测试上述方式会对公共接口的所有方法进行拦截:

    修改接口,添加一个方法如下:

     1 package com.hm;
     2 
     3 /**
     4  * 实际的主要的业务接口
     5  * @author Administrator
     6 */
     7 public interface IHello {
     8     
     9     void sayHello();
    10     
    11     void sayHelloToo();
    12 
    13 }

    仅仅在HelloImpl中实现该方法:

    1     @Override
    2     public void sayHelloToo() {
    3         System.out.println("say hello too");
    4     }

    修改ClientTest中test1()方法

     1     static void test1(){
     2         //创建代理工厂
     3         ProxyFactory pf = new ProxyFactory();
     4         //射入目标类对象
     5         pf.setTarget(new HelloImpl());
     6         //添加前置增强
     7         pf.addAdvice(new HelloBeforeAdvice());
     8         //添加后置增强
     9         pf.addAdvice(new HelloAfterAdvice());
    10         //从方法中获取代理
    11         IHello hello = (IHello) pf.getProxy();
    12         //调用代理的方法
    13         hello.sayHello();
    14         hello.sayHelloToo();
    15     }

    仅仅需要调用一下sayHelloToo方法即可

    其他实现了IHello接口的实现类不要改动

    此时HelloImpl实现了两个方法:sayHello()和sayHelloToo(),运行ClientTest中的test1()方法,结果如下:

    Before in HelloBeforeAdvice

    hello in helloImpl  (注意这个)

    After in HelloAfterAdvice

    Before in HelloBeforeAdvice

    say hello too  (注意这个)

    After in HelloAfterAdvice

    可以看出,两个方法均被拦截(增强)了,故上述方式会对被代理类的所有接口实现类进行增强

    还原回原来的IHello,HelloImpl,ClientTest代码吧

    AOP切面

    由上面的测试可以看出之前的代理都是对类级别的拦截,会拦截类里面的所有方法,而在实际情况中,一般只需要拦截特定的方法就行了,这里需要引入Advisor切面的概念了,它是将增强类与拦截匹配条件组合在一起,然后将这个切面配置到ProxyFactory中,从而生成代理。

    既然需要拦截特定的方法,那么肯定需要提供一个拦截的条件,即什么样的方法可以被增强,Spring AOP提供了一些切面类,最常见的就是正则表达式的切面类,实例如下:

    在HelloImpl中添加两个方法,一个以good开头,另一个不是,并且都不是接口中的方法,如下:

     1     /**
     2      * 该方法以good开头,故调用的时候会被拦截(增强),可以参见beans.xml的配置
     3      */
     4     public void goodMorning(){
     5         System.out.println("goodMorning in HelloImpl");
     6     }
     7     
     8     /**
     9      * 为了区分goodMorning方法,该方法不以good开头,故调用的时候不会被拦截(增强)
    10      */
    11     public void notGoodAfternoon(){
    12         System.out.println("not goodMorning in HelloImpl");
    13     }

    在beans.xml中添加bean配置:

     1 <!-- 配置一个切面 -->
     2     <bean id="helloAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     3         <property name="advice" ref="HelloAroundAdvice"></property>
     4         <property name="pattern" value="com.hm.HelloImpl.good.*"></property>
     5     </bean>
     6     
     7     <!-- 配置一个代理 -->
     8     <bean id="helloImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
     9         <property name="target" ref="HelloImpl"></property>
    10         <property name="interceptorNames" value="helloAdvisor"></property>
    11         <property name="ProxyTargetClass" value="true"></property>
    12     </bean>

    其中

    <property name="pattern" value="com.hm.HelloImpl.good.*"></property>

    com.hm.HellImpl.good.*表示匹配HelloImpl类中以good开头的方法,即拦截这些被匹配了的方法

    在ClientTest中添加方法:

     1     /**
     2      * 测试自定义方法增强(拦截)
     3      */
     4     static void test7(){
     5         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
     6         //这里转为目标类,而不是它的接口类
     7         HelloImpl helloImpl = (HelloImpl) context.getBean("helloImplProxy");
     8         helloImpl.sayHello();
     9         System.out.println("-------------------------");
    10         //可以看出只有goodMorning方法被拦截(增强)了
    11         helloImpl.goodMorning();
    12         System.out.println("-------------------------");
    13         helloImpl.notGoodAfternoon();
    14     }

    在main方法中运行:

    hello in helloImpl

    -------------------------

    before in HelloAroundAdvice

    goodMorning in HelloImpl

    after in HelloAroundAdvice

    -------------------------

    not goodMorning in HelloImpl

    可以看出只有以good开头的方法被拦截(增强)了

    待续。。

     工程截图:

    jar包截图:

  • 相关阅读:
    Revolving Digits[EXKMP]
    字符加密Cipher(bzoj 1031)
    Hotaru's problem
    1089 最长回文子串 V2(Manacher算法)
    3172: [Tjoi2013]单词
    3689: 异或之
    3942: [Usaco2015 Feb]Censoring [KMP]
    2795: [Poi2012]A Horrible Poem
    GT考试(bzoj 1009)
    NOIP2016提高组解题报告
  • 原文地址:https://www.cnblogs.com/seguzhizi/p/5053932.html
Copyright © 2020-2023  润新知