spring之aop

AOP中关键性概念
连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出.

目标(Target):被通知(被代理)的对象
注1:完成具体的业务逻辑

通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)
注2:完成切面编程

代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),
例子:外科医生+护士
注3:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的

切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点。
(也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)

适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)

 

 

代码:

IBookBiz 接口:

package com.xhp.aop.biz;

public interface IBookBiz {
    // 购书
    public boolean buy(String userName, String bookName, Double price);

    // 发表书评
    public void comment(String userName, String comments);
}

 BookBizImpl :

1 package com.xhp.aop.biz.impl;
 2 
 3 import com.xhp.aop.biz.IBookBiz;
 4 import com.xhp.aop.ex.PriceException;
 5 
 6 public class BookBizImpl implements IBookBiz {
 7 
 8     public BookBizImpl() {
 9         super();
10     }
11 
12     public boolean buy(String userName, String bookName, Double price) {
13         // 通过控制台的输出方式模拟购书
14         if (null == price || price <= 0) {
15             throw new PriceException("book price exception");
16         }
17         System.out.println(userName + " buy " + bookName + ", spend " + price);
18         return true;
19     }
20 
21     public void comment(String userName, String comments) {
22         // 通过控制台的输出方式模拟发表书评
23         System.out.println(userName + " say:" + comments);
24     }
25 
26 }

 spring-context.xml配置:

<?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     default-autowire="byName"
 5     xmlns:context="http://www.springframework.org/schema/context"
 6     xmlns:tx="http://www.springframework.org/schema/tx"
 7     xmlns:aop="http://www.springframework.org/schema/aop"
 8     xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
 9        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
10        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
11        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
12     <bean class="com.xhp.ioc.biz.impl.UserBizImpl2" id="userBiz"></bean>
13     <bean class="com.xhp.ioc.web.UserAction" id="yyy">
14       <!-- set注入用property标签 -->
15       <!-- <property name="userBiz" ref="userBiz"></property> -->
16       <!-- <property name="uname" value="zs"></property>
17       <property name="age" value="19"></property> -->
18       <!-- 构造注入用constructor-arg标签 -->
19       <constructor-arg name="uname" value="ls"></constructor-arg>
20       <constructor-arg name="age" value="19"></constructor-arg>
21       <property name="hobby">
22         <list>
23           <value>游戏</value>
24           <value>听歌</value>
25           <value>篮球</value>
26         </list>
27       </property>
28     </bean>
29     
30     
31     <bean class="com.xhp.ioc.web.OrderAction" id="xxx">
32       <!-- <property name="userBiz" ref="userBiz"></property> -->
33     </bean>
34     
35     <!-- ************************** AOP ************************************** -->
36     <!-- 目标对象 -->
37     <bean id="bookBiz" class="com.xhp.aop.biz.impl.BookBizImpl"></bean>
38     <!-- 通知 -->
39     <!-- 前置通知 -->
40     <bean id="myBefore" class="com.xhp.aop.advice.MyMethodBeforeAdvice"></bean>
41     <!-- 后置通知 -->
42     <bean id="myAfter" class="com.xhp.aop.advice.MyAfterReturningAdvice"></bean>
43     <!-- 环绕通知 -->
44     <bean id="myInterceptor" class="com.xhp.aop.advice.MyMethodInterceptor"></bean>
45     <!-- 异常通知 -->
46     <bean id="myThrowsAdvice" class="com.xhp.aop.advice.MyThrowsAdvice"></bean>
47     <!-- 过滤通知 -->
48     <bean id="myAfter2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
49         <property name="advice" ref="myAfter"></property>
50         <property name="pattern" value=".*buy"></property>
51     </bean>
52     
53     <!-- 由代理工厂来组装目标对象及通知 -->
54     <bean id="bookProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
55         <property name="target" ref="bookBiz"></property>
56         <property name="proxyInterfaces">
57             <list>
58                 <value>com.xhp.aop.biz.IBookBiz</value>
59             </list>
60         </property>
61         <property name="interceptorNames">
62             <list>
63                 <value>myBefore</value>
64 <!--                 <value>myAfter</value> -->
65                 <value>myAfter2</value>
66                 <value>myInterceptor</value>
67                 <value>myThrowsAdvice</value>
68             </list>
69         </property>
70     </bean>
71     
72 
73 
74 </beans>

测试类:

 1 package com.xhp.aop.test;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 import com.xhp.aop.biz.IBookBiz;
 7 import com.xhp.aop.biz.impl.BookBizImpl;
 8 import com.xhp.ioc.web.OrderAction;
 9 import com.xhp.ioc.web.UserAction;
10 
11 public class AopTest {
12 
13     public static void main(String[] args) {
14         
15         ApplicationContext springContext = new ClassPathXmlApplicationContext("/spring-context.xml");
16         IBookBiz bean = (IBookBiz) springContext.getBean("bookProxy");
17         System.out.println(bean.getClass());
18         boolean buy = bean.buy("张三", "圣墟", 55d);
19         bean.comment("张三", "hhhhhhhh");
20     }
21 
22 }

  前置通知:在连接点之前执行的通知()

 package com.xhp.aop.advice;
 2 
 3 import java.lang.reflect.Method;
 4 import java.util.Arrays;
 5 
 6 import org.springframework.aop.MethodBeforeAdvice;
 7 
 8 
 9 /**
10  * 买书、评论前加系统日志
11  * @author 11
12  *
13  */
14 public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
15 
16     @Override
17     public void before(Method method, Object[] args, Object target) throws Throwable {
18         String clzName = target.getClass().getName();
19         String methodName = method.getName();
20         String params = Arrays.toString(args);
21         System.out.println("【买书、评论前加系统日志】"+clzName + "." + methodName +"("+params+")");
22     }
23 
24 }

后置通知:在连接点正常完成后执行的通知

 

1 package com.xhp.aop.advice;
 2 
 3 import java.lang.reflect.Method;
 4 import java.util.Arrays;
 5 
 6 import org.springframework.aop.AfterReturningAdvice;
 7 
 8 /**
 9  * 买书返利(存在bug)
10  * @author 11
11  *
12  */
13 public class MyAfterReturningAdvice implements AfterReturningAdvice {
14 
15     @Override
16     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
17         String clzName = target.getClass().getName();
18         String methodName = method.getName();
19         String params = Arrays.toString(args);
20         System.out.println("【买书返利的后置通知】"+clzName + "." + methodName +"("+params+")"+"\t目标对象方法调用后的返回值"+returnValue);
21     }
22 
23     
24 
25 }

环绕通知:

package com.xhp.aop.advice;
 2 
 3 import java.util.Arrays;
 4 
 5 import org.aopalliance.intercept.MethodInterceptor;
 6 import org.aopalliance.intercept.MethodInvocation;
 7 import org.omg.PortableInterceptor.INACTIVE;
 8 
 9 public class MyMethodInterceptor implements MethodInterceptor {
10 
11     @Override
12     public Object invoke(MethodInvocation invocation) throws Throwable {
13         String clzName = invocation.getThis().getClass().getName();
14         String methodName = invocation.getMethod().getName();
15         String params = Arrays.toString(invocation.getArguments());
16         System.out.println("【环绕通知】"+clzName + "." + methodName +"("+params+")");
17         Object returnValue = invocation.proceed();
18         System.out.println("【环绕通知】:\t目标对象方法调用后的返回值"+returnValue);
19         return returnValue;
20     }
21 
22 }

 异常通知:这个通知会在方法抛出异常退出时执行

 package com.xhp.aop.advice;
 2 
 3 import org.springframework.aop.ThrowsAdvice;
 4 
 5 import com.xhp.aop.ex.PriceException;
 6 
 7 /**
 8  * 异常通知
 9  * @author 11
10  *
11  *案例:张三向李四转账
12  *    biz.transfer(user1,user2)
13  *        UserDao.update(user1)
14  *        UserDao.update(user2)
15  *
16  *
17  */
18 public class MyThrowsAdvice implements ThrowsAdvice {
19 
20     public void afterThrowing( PriceException ex) {
21         System.out.println("价格输入有无,购买失效,请重新输入!!!");
22      }
23     
24     
25     
26 }
 适配器=通知(Advice)+切入点(Pointcut)
 案例:通过适配器解决发书评时也返利的问题
   适配器不需要创建类,只需要在spring-context.xml中配置bean就OK了
 1 <!-- bean配置 -->
 2 <bean id="myAfter2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
 3         <property name="advice" ref="myAfter"></property>
 4         <property name="pattern" value=".*buy"></property>
 5     </bean>
 6 
 7 然后将代理工厂中value为myAfter替换成myAfter2
 8                 <value>myBefore</value>
 9 <!--            <value>myAfter</value> -->
10                 <value>myAfter2</value>
11                 <value>myInterceptor</value>
12                 <value>myThrowsAdvice</value>

 

posted @ 2019-08-18 19:15  WhM4c  阅读(109)  评论(0编辑  收藏  举报