• 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>
  • 相关阅读:
    maria-developers 开发者邮件
    Parallel Programming--perfbook
    面向对象设计模式中类与类关系
    binlog 轻松的找到没有及时提交的事物(infobin工具
    deeplearningbook-chinese
    Introduction to the Optimizer --cbo
    dell T420热插拔安装过程
    MySQL是如何利用索引的
    BTrace housemd TProfiler
    杨建荣的学习笔记
  • 原文地址:https://www.cnblogs.com/alphajuns/p/10041361.html
Copyright © 2020-2023  润新知