Spring框架中的AOP技术----配置文件方式

1、AOP概述

AOP技术即Aspect Oriented Programming的缩写,译为面向切面编程。AOP是OOP的一种延续,利用AOP技术可以对业务逻辑的各个部分进行隔离,从使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时提高了开发的效率。

AOP采用横向抽取机制,取代了传统纵向继承体系重复性代码,AOP可以在不修改源代码的前提下,对程序进行增强。

2、AOP技术的底层实现

  1. 基于jdk的动态代理:必须是面向接口的,只有实现了具体接口的类才能生成代理对象
  2. 基于CGLIB动态代理:对于没有实现接口的类,也可以产生代理,产生这个类的子类的方式

Spring的传统AOP中根据类是否实现接口而采用不同的代理方式,如果实现类接口,则使用jdk动态代理完成AOP,如果没有实现接口,采用CGLIB动态代理完成AOP。

JDK动态代理演示:

接口UserDao、实现类UserDaoImpl、动态代理类MyProxyUtils

1 package com.alphajuns.demo1;
2 
3 public interface UserDao {
4 
5     public void save();
6     
7     public void update();
8     
9 }
 1 package com.alphajuns.demo1;
 2 
 3 public class UserDaoImpl implements UserDao {
 4 
 5     @Override
 6     public void save() {
 7         System.out.println("保存用户...");
 8     }
 9 
10     @Override
11     public void update() {
12         System.out.println("修改用户...");
13     }
14 
15 }
 1 package com.alphajuns.demo1;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 /*
 8  * 使用JDK的方式生成动态代理
 9  */
10 public class MyProxyUtils {
11 
12     public static UserDao getProxy(final UserDao dao) {
13         // 使用Proxy类生成代理对象
14         UserDao proxy = (UserDao) Proxy.newProxyInstance(
15                 dao.getClass().getClassLoader(),
16                 dao.getClass().getInterfaces(),
17                 new InvocationHandler() {
18                     
19                     @Override
20                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
21                         if ("save".equals(method.getName())) {
22                             System.out.println("记录日志...");
23                         }
24                         // 执行dao类中的方法
25                         return method.invoke(dao, args);
26                     }
27                 });
28         
29         // 返回代理对象
30         return proxy;
31     }
32     
33 }

CGLIB代理:

 1 package com.alphajuns.demo2;
 2 
 3 import java.lang.reflect.Method;
 4 
 5 import org.springframework.cglib.proxy.Enhancer;
 6 import org.springframework.cglib.proxy.MethodInterceptor;
 7 import org.springframework.cglib.proxy.MethodProxy;
 8 
 9 public class MyCglibUtils {
10 
11     /*
12      * 使用Cglib方法生成代理对象
13      */
14     public static BookDaoImpl getProxy() {
15         Enhancer enhancer = new Enhancer();
16         // 设置父类
17         enhancer.setSuperclass(BookDaoImpl.class);
18         // 设置回调函数
19         enhancer.setCallback(new MethodInterceptor() {
20             // 代理对象的方法执行,回调函数的方法就会执行
21             @Override
22             public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
23                 if ("save".equals(method.getName())) {
24                     System.out.println("记录日志...");
25                 }
26                 // 正常执行
27                 return methodProxy.invokeSuper(obj, args);
28             }
29         });
30         
31         // 生成代理对象
32         BookDaoImpl proxy = (BookDaoImpl) enhancer.create();
33         return proxy;
34     }
35     
36 }

3、AOP相关术语

  1. JoinPoint(连接点):被拦截的点。Spring中,这些点是指方法,Spring只支持方法类型的连接点。
  2. Pointcut(切入点):对需要被拦截的JoinPoint的定义。
  3. Advice(通知/增强):拦截到JointPoint之后所要做的事情就是通知。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知
  4. Introduction(引介):引介是一种特殊的通知,在不修改代码的前提下,Introduction可以在运行期为类动态地添加一些方法或field
  5. Target(目标对象):代理的目标对象
  6. Weaving(织入):是指增强应用到目标对象来创建新的代理对象的过程
  7. Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
  8. Aspect(切面):切入点与通知的结合

4、XML方式AOP开发步骤

  1. 创建WEB项目,引入jar包
  2. 创建Spring配置文件,引入AOP的schema约束
  3. 创建包结构,编写具体的接口和实现类
  4. 将目标类配置到Spring配置文件中
  5. 定义切面类
  6. 在配置文件中定义切面类
  7. 在配置文件中完成AOP配置
  8. 测试

5、切入点表达式

切入点表达式在下面applicationContext2中以注释形式进行了介绍。

6、AOP通知类型

  1. 前置通知:在目标类的方法执行之前执行
  2. 后置通知:在目标类方法执行之后执行
  3. 异常抛出通知:在抛出异常后通知
  4. 环绕通知:方法执行前后都执行

7、AOP应用举例

接口CustomerDao、实现类CustomerDaoImpl、切面类MyAspectXml、Spring配置文件applicationContext、applicationContext2、applicationContext3

1 package com.alphajuns.demo3;
2 
3 public interface CustomerDao {
4 
5     public void save();
6     
7     public void update();
8     
9 }
 1 package com.alphajuns.demo3;
 2 
 3 public class CustomerDaoImpl implements CustomerDao {
 4 
 5     @Override
 6     public void save() {
 7         System.out.println("保存客户...");
 8     }
 9 
10     @Override
11     public void update() {
12         System.out.println("更新客户...");
13     }
14 
15 }
 1 package com.alphajuns.demo3;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 
 5 /*
 6  * 切面类:切入点+通知
 7  */
 8 public class MyAspectXml {
 9 
10     /*
11      * 通知(具体的增强)
12      */
13     public void log() {
14         System.out.println("记录日志...");
15     }
16     
17     /*
18      * 最终通知:方法执行成功或出现异常,都会执行
19      */
20     public void after() {
21         System.out.println("最终通知...");
22     }
23     
24     /*
25      * 后置通知:方法执行之后,执行后置通知,出现异常则不执行
26      */
27     public void afterReturn() {
28         System.out.println("后置通知...");
29     }
30     
31     /*
32      * 环绕通知:方法执行之前和方法执行之后进行通知,默认情况下,目标对象的方法不执行。需要手动让目标对象的方法执行
33      */
34     public void around(ProceedingJoinPoint joinPoint) {
35         System.out.println("环绕通知1...");
36         try {
37             // 手动让目标对象的方法执行
38             joinPoint.proceed();
39         } catch (Throwable e) {
40             e.printStackTrace();
41         }
42         System.out.println("环绕通知2...");
43     }
44     
45 }

 

 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     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
 7 
 8     <!-- 配置客户的dao -->
 9     <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/>
10     <!-- 配置切面类 -->
11     <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/>
12     <!-- 配置AOP -->
13     <aop:config>
14         <!-- 配置切面类:切入点+通知类型 -->
15         <aop:aspect ref="myAspectXml">
16             <!-- 配置前置通知 -->
17             <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/>
18         </aop:aspect>
19     </aop:config>
20 
21 </beans>
 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     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
 7 
 8     <!-- 配置客户的dao -->
 9     <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/>
10     <!-- 配置切面类 -->
11     <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/>
12     <!-- 配置AOP -->
13     <aop:config>
14         <!-- 配置切面类:切入点+通知类型 -->
15         <aop:aspect ref="myAspectXml">
16             <!-- 配置前置通知 -->
17             <!-- 切入点的表达式
18                 1、execution() 固定的,不能不写
19                 2、public 可以省略不写
20                 3、void出可以用*替代,表示返回值类型任意,不能省略不写
21                 4、包的简写方式
22                 5、类的写法
23                 6、方法的写法
24                 7、方法的参数
25              -->
26             <!-- 完整写法 -->
27             <!-- <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
28             <!-- public可以省略不写 -->
29             <!-- <aop:before method="log" pointcut="execution(void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
30             <!-- void出用*替代 -->
31             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
32             <!-- 包的写法 -->
33             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
34             <!-- 包的写法 -->
35             <!-- <aop:before method="log" pointcut="execution(* *..*.CustomerDaoImpl.save())"/> -->
36             <!-- 类的写法 -->
37             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.*DaoImpl.save())"/> -->
38             <!-- 方法写法 -->
39             <!-- <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.*save())"/> -->
40             <!-- 方法的参数 -->
41             <aop:before method="log" pointcut="execution(* com.alphajuns.demo3.CustomerDaoImpl.*save(..))"/>
42         </aop:aspect>
43     </aop:config>
44 
45 </beans>
 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     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
 7 
 8     <!-- 配置客户的dao -->
 9     <bean id="customerDao" class="com.alphajuns.demo3.CustomerDaoImpl"/>
10     <!-- 配置切面类 -->
11     <bean id="myAspectXml" class="com.alphajuns.demo3.MyAspectXml"/>
12     <!-- 配置AOP -->
13     <aop:config>
14         <!-- 配置切面类:切入点+通知类型 -->
15         <aop:aspect ref="myAspectXml">
16             <!-- 配置前置通知 -->
17             <!-- <aop:before method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
18             <!-- 配置后置通知 -->
19             <!-- <aop:after method="log" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/> -->
20             <!-- 环绕通知 -->
21             <aop:around method="around" pointcut="execution(public void com.alphajuns.demo3.CustomerDaoImpl.save())"/>
22         </aop:aspect>
23     </aop:config>
24 
25 </beans>

 

posted @ 2018-11-29 22:22  AlphaJunS  阅读(517)  评论(0编辑  收藏  举报