【Spring】AOP

引入

  为了将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,Spring提供了面向切面的编程方式,也称Spring AOP。它有效地减少了系统间的重复代码,实现了模块间的松耦合。

简介

  AOP全称为Aspect Oriented Programming,即面向切面编程。AOP采用横向抽取机制,主要体现在事务处理,日志管理、权限控制、异常处理等方面,使开发人员在编写业务逻辑时可以专心于核心业务,提高了代码的可维护性。
  目前最流行的AOP框架有两个,分别为Spring AOP和AspectJ。Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类织入增强的代码。AspectJ是一个基于Java语言的AOP框架,提供了一个专门的编译器,在编译时提供横向代码的织入。

AOP术语

  AOP的专业术语包括Joinpoint、PointCut、Advice、Target、Weaving、Proxy和Aspect,各名词解释如下:

  • Joinpoint(连接点):类中的方法。
  • Pointcut(切入点):是指要对哪些Joinpoint进行拦截,即被拦截的连接点。
  • Advice(通知):在某个特定的Pointcut上需要执行的动作。如日志记录、权限验证等。
  • Target(目标):是指代理的对象。
  • Weaving(织入):是指把增强代码应用到目标上,生成代理对象的过程。
  • Proxy(代理):是指生成的代理对象。
  • Aspect(切面):是指切入点和通知的结合。

五种通知

  • before:前置通知。目标方法执行前执行。
  • after:后置通知。目标方法执行后执行。
  • after returning:后置返回通知。目标方法返回时执行。
  • after throwing:异常通知。目标方法抛出异常时执行。
  • around:环绕通知。在目标函数执行中执行,可控制目标函数是否执行。

示例

public class HelloWorld {
    public void sayHelloWorld(){
        System.out.println("Hello World!");
    }
    public void sayHelloSpring(){
        System.out.println("Hello Spring!");
    }
}
public class MyAspect {
    public void myBefore(JoinPoint joinPoint){
        System.out.println("方法执行前......");
    }
    public void myAfter(JoinPoint joinPoint){
        System.out.println("方法执行后......");
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 1.目标类 -->
    <bean id="helloWorld" class="cn.jujianfei.project.demo2.HelloWorld"></bean>
    <!-- 2.切面 -->
    <bean id="myAspect" class="cn.jujianfei.project.demo2.MyAspect"></bean>
    <!-- 3.aop配置 -->
    <aop:config>
        <aop:aspect ref="myAspect">
            <!-- 3.1 配置切入点,通知最后增强哪些方法 -->
            <aop:pointcut id="myPointcut" 
                expression="execution(* cn.jujianfei.project.demo2.HelloWorld.*(..))"></aop:pointcut>
            <!-- 3.2 关联通知Advice和切入点Pointcut-->
            <aop:before method="myBefore" pointcut-ref="myPointcut"></aop:before>
            <aop:after method="myAfter" pointcut-ref="myPointcut"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

单元测试

 @Test
 public void test5(){
     ApplicationContext applicationContext = new ClassPathXmlApplicationContext("demo1.xml");
     HelloWorld hello = (HelloWorld)applicationContext.getBean("helloWorld");
     hello.sayHelloWorld();
     hello.sayHelloSpring();
 }

打印结果

这里写图片描述

Execution函数

  配置文件中的execution函数用来匹配切入点。语法结构为(其中,访问修饰符、类全路径、异常类型可选):

execution([访问修饰符] [返回值类型] [类全路径].[方法名](参数类型) 异常类型)

  官方文档语法结构:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
            throws-pattern?)

通配符的含义

  • .. :匹配方法定义中任意数量的参数,此外还可以匹配类定义中任意数量的包。
  • *:匹配任意数量的字符。

示例

//匹配任意返回值,任意名称,任意参数的公共方法
execution(public * *(..))
//匹配以set开头,参数为int类型,任意返回值的方法
execution(* set*(int))
//匹配在service包或其子包下的任意方法
execution(* com.xyz.service..*.*(..))
//匹配UserDaoImpl类中的所有方法
execution(* com.zejian.dao.UserDaoImpl.*(..))
//匹配UserDaoImpl类中的所有公共的方法
execution(public * com.zejian.dao.UserDaoImpl.*(..))
//匹配UserDaoImpl类中的所有返回值为int类型的公共方法
execution(public int com.zejian.dao.UserDaoImpl.*(..))
//匹配UserDaoImpl类中第一个参数为int类型的所有公共的方法
execution(public * com.zejian.dao.UserDaoImpl.*(int , ..))

基于注解的Spring AOP

@Component
public class HelloWorld {
    public void sayHelloWorld(){
        System.out.println("Hello World!");
    }
    public void sayHelloSpring(){
        System.out.println("Hello Spring!");
    }
}
@Aspect
@Component
public class MyAspect {
    @Pointcut("execution(* cn.jujianfei.project.demo3.HelloWorld.*(..))")
    private void myPointCut(){}
    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("方法执行前......");
    }
    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint){
        System.out.println("方法执行后......");
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:demo2.xml")
public class MyTest {
    @Autowired
    private HelloWorld helloWorld;
    @Test
    public void test(){
        helloWorld.sayHelloWorld();
        helloWorld.sayHelloSpring();
    }
}

打印结果不变。


参考资料: https://blog.csdn.net/nvd11/article/details/51835717
参考资料: https://blog.csdn.net/javazejian/article/details/56267036
参考资料: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop

猜你喜欢

转载自blog.csdn.net/gnd15732625435/article/details/81004794