Spring第三章:Spring AOP

本文详细介绍了Spring AOP的基础概念、实现原理(包括JDK动态代理和CGLIB)、通知类型、切面类型,以及自动代理的两种策略。涵盖了传统AOP的实战配置和使用实例,帮助开发者理解和运用面向切面编程技术提升代码复用性和可维护性。
摘要由CSDN通过智能技术生成

该系列为imooc Spring从入门到进阶笔记,跟随课程加入自己见解,同时也为项目中碰到一些问题做了解答

1、AOP的概述

1.1、什么是AOP

  • Aspect Oriented Programing 面向切面编程
  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
  • 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。
  • 可用于性能监视、事务管理、安全检查、缓存
  • 使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码

AOP横向抽取机制与纵向继承方式的对比
在这里插入图片描述

1.2、AOP相关术语

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点

Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义

Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field

Target(目标对象):被代理的目标对象

Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程,spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

Aspect(切面): 是切入点和通知(引介)的结合

在这里插入图片描述

2、AOP的底层实现

2.1、JDK的动态代理

Java动态代理位于java.lang.reflect包下,一般主要涉及到以下两个类:

  • Interface InvocationHandler
    该接口中仅定义了一个方法:public Object invoke(Object obj, Method method, Object[] args),在使用时,第一个参数obj一般是指被代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

  • Proxy
    该类即为动态代理类,static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h),该方法有三个参数,分别是当前类的CalssLoad,当前类实现的接口,接口InvocationHandler。该方法返回代理类的一个实例,返回后的代理类可以当作被代理类使用。

我们调用被代理类当中的各种方法,都相当于调用代理类的invoke方法,所以我们控制invoke就可以

JDK动态代理的一般实现步骤如下:

  1. 创建一个实现InvocationHandler接口的类,它必须实现invoke方法

  2. 创建被代理的类以及接口

  3. 调用Proxy的静态方法newProxyInstance,创建一个代理类实例

  4. 通过代理类实例调用方法

JDK动态代理的简易实现

  1. 使用idea Maven创建Web项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 在项目pom文件中配置junit依赖
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
  1. 编写代码
    在main下新建java文件夹,右键java文件夹
    在这里插入图片描述
  2. 在java文件夹>新建com.imooc.aop.demo1包>新建UserDao 接口
package com.imooc.aop.demo1;

public interface UserDao {
    public void save();

    public void update();

    public void delete();

    public void find();
}

  1. 在java文件夹>com.imooc.aop.demo1包>新建UserDaoImpl 类(UserDao的实现)(被代理类)
package com.imooc.aop.demo1;

public class UserDaoImpl implements UserDao{
    public void save() {
        System.out.println("保存用户...");
    }

    public void update() {
        System.out.println("修改用户...");
    }

    public void delete() {
        System.out.println("删除用户...");
    }

    public void find() {
        System.out.println("查询用户...");
    }
}
  1. 在java文件夹>com.imooc.aop.demo1包>新建MyJdkProxy 类(代理类,增强被代理类的save()方法)
package com.imooc.aop.demo1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyJdkProxy implements InvocationHandler {
    private UserDao userDao;

    public MyJdkProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    public Object createProxy(){
        Object proxy=Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(),this);
        return proxy;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("save".equals(method.getName())){
            System.out.println("权限校验...");
            return method.invoke(userDao,args);
        }
        return method.invoke(userDao,args);
    }
}

  1. 在java文件夹>com.imooc.aop.demo1包>新建SpringDemo1 类(测试类)
package com.imooc.aop.demo1;

import org.junit.Test;

public class SpringDemo1 {
    @Test
    public void demo1(){
        UserDao userDao=new UserDaoImpl();

        UserDao proxy=(UserDao) new MyJdkProxy(userDao).createProxy();

        proxy.save();
        proxy.update();
        proxy.delete();
        proxy.find();
    }
}

启动测试代码
在这里插入图片描述
可见被代理类的save()方法被增强了

2.2、CGLIB的动态代理

  • 对于不使用接口的业务类,无法使用JDK动态代理
  • CGlib采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题

CGLIB创建代理的步骤

  1. 创建核心类
Enhancer enhancer = new Enhancer();
  1. 设置父类
enhancer.setSuperclass(); //设置目标类为父类
  1. 设置回调
enhancer.setCallback(MethodInterface的实现类);
  1. 生成代理
Object proxy = enhancer.create();
return proxy;
  1. 重写intercept()方法
public Object intercept(Object proxy, Methid method, Object[] args, MethodProxy methodProxy) throws Throwable {
//增强代码
methodProxy.invokeSuper(proxy, args);
}
  1. 创建代理类并执行其中方法
ProductDao proxy = (ProductDao) new MyCglibProxy(代理对象).createProxy();

CGLIB动态代理的简易实现

  1. 在项目pom文件中配置junit依赖
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
  1. 在java文件夹>新建com.imooc.aop.demo2包>新建ProductDao 类(被代理类)
package com.imooc.aop.demo2;

public class ProductDao {
    public void save(){
        System.out.println("保存商品...");
    }

    public void update(){
        System.out.println("修改商品...");
    }

    public void delete(){
        System.out.println("删除商品...");
    }

    public void find(){
        System.out.println("查新商品...");
    }
}

  1. 在java文件夹>新建com.imooc.aop.demo2包>新建MyCglibProxy类(代理类)
package com.imooc.aop.demo2;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyCglibProxy implements MethodInterceptor {
    private ProductDao productDao;

    public MyCglibProxy(ProductDao productDao){
        this.productDao=productDao;
    }
    public Object createProxy(){
        //1、创建核心类
        Enhancer enhancer=new Enhancer();
        //2、设置父类
        enhancer.setSuperclass(productDao.getClass());
        //3、设置回调
        enhancer.setCallback(this);
        //4、生成代理
        Object proxy=enhancer.create();
        return proxy;
    }

	//5、重写intercept()方法
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        if ("save".equals(method.getName())){
            System.out.println("=========权限校验=========");
            return methodProxy.invokeSuper(proxy,args);
        }

        return methodProxy.invokeSuper(proxy,args);
    }
}

  1. 在java文件夹>新建com.imooc.aop.demo2包>新建SpringDemo2类(测试代码)
package com.imooc.aop.demo2;

import org.junit.Test;

public class SpringDemo2 {
    @Test
    public void demo1(){
        ProductDao productDao=new ProductDao();

        ProductDao proxy=(ProductDao)new MyCglibProxy(productDao).createProxy();

        proxy.save();

        proxy.update();

        proxy.delete();

        proxy.find();
    }
}

启动测试
在这里插入图片描述
可见被代理类的save()方法被增强了

2.3、代理知识的总结

  • Spring在运行期,生成动态代理对象,不需要特殊的编译器

  • Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术 为目标Bean执行横向织入

    1. 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
    2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
  • 程序中应优先对接口创建代理,便于程序解耦维护

  • 标记为final的方法,不能被代理,因为无法进行覆盖

    1. JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
    2. CGLib 是针对目标类生产子类,因此类或方法 不能使final的
  • Spring只支持方法连接点,不提供属性连接

3、 Spring的传统AOP

3.1、Spring的AOP的通知类型介绍

  • AOP联盟为通知Advice定义了org.aopalliance.aop.Interface.Advice

  • Spring按照通知Advice在目标类方法的连接点位置,可以分为5类

    1. 前置通知 org.springframework.aop.MethodBeforeAdvice
      在目标方法执行前实施增强

    2. 后置通知 org.springframework.aop.AfterReturningAdvice
      在目标方法执行后实施增强

    3. 环绕通知 org.aopalliance.intercept.MethodInterceptor
      在目标方法执行前后实施增强

    4. 异常抛出通知 org.springframework.aop.ThrowsAdvice
      在方法抛出异常后实施增强

    5. 引介通知 org.springframework.aop.IntroductionInterceptor
      在目标类中添加一些新的方法和属性

3.2、Spring AOP切面类型

  • Advisor : 代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截

  • PointcutAdvisor : 代表具有切点的切面,可以指定拦截目标类哪些方法

  • IntroductionAdvisor : 代表引介切面,针对引介通知而使用切面(不要求掌握)

3.3、不带切入点的切面(Advisor一般切面)

在applicationContext.xml中配置增强

Spring提供了一个类(org.springframework.aop.framework.ProxyFactoryBean),专门用于产生代理对象,是在bean标签>property标签进行属性配置

  • target : 代理的目标对象

  • interceptorNames : 需要织入目标的Advice

  • proxyTargetClass : 是否对类代理而不是接口,设置为true时,使用CGLib代理

  • singleton : 返回代理是否为单实例,默认为单例

  • optimize : 当设置为true时,强制使用CGLib

  • proxyInterfaces : 代理要实现的接口

    • 如果多个接口可以使用以下格式赋值
<list>
 <value></value>
 ....
</list>

使用Spring AOP的配置实现简易的Advisor切面案例

  1. 在项目POM文件中引入依赖
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
  1. 在java文件夹>新建com.imooc.aop.demo3包>新建StudentDao接口
package com.imooc.aop.demo3;

public interface StudentDao {
    public void save();

    public void update();

    public void delete();

    public void find();
}

  1. 在java文件夹>com.imooc.aop.demo3包>新建StudentDaoImpl 类(StudentDao的实现类)(被代理的类)
package com.imooc.aop.demo3;

public class StudentDaoImpl implements StudentDao{
    public void save() {
        System.out.println("学生保存...");
    }

    public void update() {
        System.out.println("学生修改...");
    }

    public void delete() {
        System.out.println("学生删除...");
    }

    public void find() {
        System.out.println("学生查询...");
    }
}

  1. 在java文件夹>com.imooc.aop.demo3包>新建MyBeforeAdvice类(前置增强方法所在的类)
package com.imooc.aop.demo3;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("=================这是前置增强================");
    }
}

  1. 在resources下>新建applicationContext.xml(Spring配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--============配置目标类=============-->
    <bean id="studentDaoImpl" class="com.imooc.aop.demo3.StudentDaoImpl"/>

    <!--============配置通知=============-->
    <bean id="myBeforeAdvice" class="com.imooc.aop.demo3.MyBeforeAdvice"/>

    <!--============配置Spring的AOP产生代理对象=============-->
    <bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

        <!--============配置被代理的目标类=============-->
        <property name="target" ref="studentDaoImpl"/>

        <!--============配置被代理的目标类所实现的接口=============-->
        <property name="proxyInterfaces" value="com.imooc.aop.demo3.StudentDao"/>

        <!--============配置采用拦截的名称(采用切面拦截,该项目为不带切入点,即所有方法都被增强,故只配置通知即可)=============-->
        <property name="interceptorNames" value="myBeforeAdvice"/>
    </bean>
</beans>
  1. 在java文件夹>com.imooc.aop.demo3包>新建SpringDemo3类(测试代码)
package com.imooc.aop.demo3;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
//    @Resource(name = "studentDaoImpl")//注入被代理类,无增强
    @Resource(name = "studentDaoProxy")//注入代理类,实现增强
    private StudentDao studentDao;

    @Test
    public void demo1(){
        studentDao.find();
        studentDao.save();
        studentDao.update();
        studentDao.delete();
    }
}

关于两个注解的含义,大神写的文章
@RunWith的使用
@ContextConfiguration的意思

启动测试
在这里插入图片描述

可见Advisor一般切面的简易实现成功了

3.4、带有切入点的切面(PointcutAdvisor 切点切面)

使用普通Advice作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用 带有切点的切面

常用PointcutAdvisor 实现类

  • Default PointcutAdvisor 最常用的切面类型,它可以通过任意Pointcut和Advice 组合定义切面
  • Jdk RegexpMethodPointcut 构造正则表达式切点

使用Spring AOP的配置实现简易的Jdk RegexpMethodPointcut类型的切面案例

  1. 在java文件夹>新建com.imooc.aop.demo4包>新建CustomerDao 类
package com.imooc.aop.demo4;

public class CustomerDao {
    public void save() {
        System.out.println("保存客户...");
    }

    public void update() {
        System.out.println("修改客户...");
    }

    public void delete() {
        System.out.println("删除客户...");
    }

    public void find() {
        System.out.println("查询客户...");
    }
}

  1. 在java文件夹>com.imooc.aop.demo4包>新建MyAroundAdvice 类(环绕通知)
package com.imooc.aop.demo4;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAroundAdvice implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("==========环绕前增强==========");

        Object obj=invocation.proceed();//执行目标自己的方法

        System.out.println("==========环绕后增强==========");
        return obj;
    }
}

  1. 在resources下>applicationContext2.xml(Spring配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--============配置目标类=============-->
    <bean id="customerDao" class="com.imooc.aop.demo4.CustomerDao"/>

    <!--============配置通知=============-->
    <bean id="myAroundAdvice" class="com.imooc.aop.demo4.MyAroundAdvice"/>

    <!--一般切面是使用通知作为切面的,如果要对目标类的某个方法进行增强就需要配置一个带有切入点的切面,配置切面-->
    <!--采用Jdk RegexpMethodPointcut实现类-->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

        <!--pattern属性表示配置切入点,属性值为正则表达式-->

        <!--value=".*"针对全部方法-->
    <!--<property name="pattern" value=".*"/>-->

        <!--value=".*save.*"针对save方法-->
    <!--<property name="pattern" value=".*save.*"/>-->

    <!--属性名称patterns用于配置多个方法-->
        <property name="patterns" value=".*save.*,.*delete.*"/>

        <!--在切面中配置通知-->
        <property name="advice" ref="myAroundAdvice"/>
    </bean>

    <!--============植入的相关配置=============-->
    <bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

        <!--============配置被代理的目标类=============-->
        <property name="target" ref="customerDao"/>

        <property name="proxyTargetClass" value="true"/>

        <!--============配置采用拦截的名称(采用切面拦截,配置切面)=============-->
        <property name="interceptorNames" value="myAdvisor"/>
    </bean>
</beans>
  1. 在java文件夹>com.imooc.aop.demo4包>新建SpringDemo4类(测试类)
package com.imooc.aop.demo4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringDemo4 {
    //@Resource(name = "customerDao")
    @Resource(name = "customerDaoProxy")
    private CustomerDao customerDao;

    @Test
    public void demo1(){
        customerDao.find();
        customerDao.save();
        customerDao.delete();
        customerDao.update();
    }
}

启动测试
在这里插入图片描述
可见带有切入点的切面案例成功

4、Spring的传统AOP的自动代理

  • 前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际
    开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大

  • 解决方案:自动创建代理

    • BeanNameAutoProxyCreator 根据Bean名称创建代理
    • DefaultAdvisorAutoProxyCreator 根据Advisor本身包含信息创建代理
    • AnnotationAwareAspectJAutoProxyCreator 基于Bean中的AspectJ 注解进行自动代理

4.1、基于Bean名称的自动代理

BeanNameAutoProxyCreator 举例

  • 对所有以DAO结尾的Bean所有方法使用代理

配置方式如下
在这里插入图片描述
对所有以DAO结尾的Bean所有方法使用代理的简易实现

  1. 在java文件夹>新建com.imooc.aop.demo5包
  2. 复制demo3中StudentDao接口、StudentDaoImpl实现类、MyBeforeAdvice前置增强类进com.imooc.aop.demo5包
package com.imooc.aop.demo5;

public interface StudentDao {
    public void save();

    public void update();

    public void delete();

    public void find();
}

package com.imooc.aop.demo5;

public class StudentDaoImpl implements StudentDao {
    public void save() {
        System.out.println("学生保存...");
    }

    public void update() {
        System.out.println("学生修改...");
    }

    public void delete() {
        System.out.println("学生删除...");
    }

    public void find() {
        System.out.println("学生查询...");
    }
}

package com.imooc.aop.demo5;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("=================这是前置增强================");
    }
}

  1. 复制demo4中CustomerDao类、MyAroundAdvice环绕增强类进com.imooc.aop.demo5包
package com.imooc.aop.demo5;

public class CustomerDao {
    public void save() {
        System.out.println("保存客户...");
    }

    public void update() {
        System.out.println("修改客户...");
    }

    public void delete() {
        System.out.println("删除客户...");
    }

    public void find() {
        System.out.println("查询客户...");
    }
}

package com.imooc.aop.demo5;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAroundAdvice implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("==========环绕前增强==========");

        Object obj=invocation.proceed();//执行目标自己的方法

        System.out.println("==========环绕后增强==========");
        return obj;
    }
}

  1. 在resources下>applicationContext3.xml(Spring配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置目标类-->
    <bean id="studentDao" class="com.imooc.aop.demo5.StudentDaoImpl"/>
    <bean id="customerDao" class="com.imooc.aop.demo5.CustomerDao"/>

    <!-- 配置增强-->
    <bean id="myBeforeAdvice" class="com.imooc.aop.demo5.MyBeforeAdvice"/>
    <bean id="myAroundAdvice" class="com.imooc.aop.demo5.MyAroundAdvice"/>

    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Dao"/>
        <property name="interceptorNames" value="myBeforeAdvice"/>
    </bean>
</beans>
  1. 在java文件夹>com.imooc.aop.demo5包>新建SpringDemo5类(测试类)
package com.imooc.aop.demo5;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class SpringDemo5 {
    @Resource(name="studentDao")
    private StudentDao studentDao;
    @Resource(name="customerDao")
    private CustomerDao customerDao;

    @Test
    public void demo1(){
        studentDao.find();
        studentDao.save();
        studentDao.update();
        studentDao.delete();

        customerDao.find();
        customerDao.save();
        customerDao.update();
        customerDao.delete();

    }
}

启动测试代码
在这里插入图片描述
对所有以DAO结尾的Bean所有方法使用代理的简易实现成功了,那如果想对某一方法进行增强,则改方式又不适用了,只能使用基于切面信息的自动代理

4.2、基于切面信息的自动代理

DefaultAdvisorAutoProxyCreator举例

  • 配置环绕代理案例
    在这里插入图片描述
    基于切面信息的自动代理的简易实现
  1. 在java文件夹>新建com.imooc.aop.demo6包
  2. 复制demo3中StudentDao接口、StudentDaoImpl实现类、MyBeforeAdvice前置增强类进com.imooc.aop.demo6包
package com.imooc.aop.demo6;

public interface StudentDao {
    public void save();

    public void update();

    public void delete();

    public void find();
}

package com.imooc.aop.demo6;

public class StudentDaoImpl implements StudentDao {
    public void save() {
        System.out.println("学生保存...");
    }

    public void update() {
        System.out.println("学生修改...");
    }

    public void delete() {
        System.out.println("学生删除...");
    }

    public void find() {
        System.out.println("学生查询...");
    }
}

package com.imooc.aop.demo6;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("=================这是前置增强================");
    }
}

  1. 复制demo4中CustomerDao类、MyAroundAdvice环绕增强类进com.imooc.aop.demo6包
package com.imooc.aop.demo6;

public class CustomerDao {
    public void save() {
        System.out.println("保存客户...");
    }

    public void update() {
        System.out.println("修改客户...");
    }

    public void delete() {
        System.out.println("删除客户...");
    }

    public void find() {
        System.out.println("查询客户...");
    }
}

package com.imooc.aop.demo6;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAroundAdvice implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("==========环绕前增强==========");

        Object obj=invocation.proceed();//执行目标自己的方法

        System.out.println("==========环绕后增强==========");
        return obj;
    }
}

  1. 在resources下>applicationContext4.xml(Spring配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置目标类-->
    <bean id="studentDao" class="com.imooc.aop.demo6.StudentDaoImpl"/>
    <bean id="customerDao" class="com.imooc.aop.demo6.CustomerDao"/>

    <!-- 配置增强-->
    <bean id="myBeforeAdvice" class="com.imooc.aop.demo6.MyBeforeAdvice"/>
    <bean id="myAroundAdvice" class="com.imooc.aop.demo6.MyAroundAdvice"/>

    <!--配置切面-->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="pattern" value="com\.imooc\.aop\.demo6\.CustomerDao\.save"/>
        <property name="advice" ref="myAroundAdvice"/>
    </bean>

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>
  1. 在java文件夹>com.imooc.aop.demo6包>新建SpringDemo6类(测试类)
package com.imooc.aop.demo6;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext4.xml")
public class SpringDemo6 {
    @Resource(name="studentDao")
    private StudentDao studentDao;
    @Resource(name="customerDao")
    private CustomerDao customerDao;

    @Test
    public void demo1(){
        studentDao.find();
        studentDao.save();
        studentDao.update();
        studentDao.delete();

        customerDao.find();
        customerDao.save();
        customerDao.update();
        customerDao.delete();

    }
}

启动测试代码
在这里插入图片描述
可见基于切面信息的自动代理的简易实现成功

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翘脚猴子耍把戏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值