由代理模式到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包截图: