[SSM -Spring Chapter 05] Using AspectJ to implement Spring AOP-(JoinPoint-Advice)

AspectJ

  AspectJ is an AOP framework based on Java language. AspectJ support has been introduced since Spring 2.0. For the current Spring framework, it is recommended to use AspectJ to implement Spring AOP.
  AOP is aspect-oriented programming, using AOP to isolate various parts of business logic, thereby reducing the coupling between various parts of business logic , improving the reusability of the program , and improving the efficiency of development at the same time

Notification type (Advice: Actions to be done before or after the method is executed)

  1. Surround notification The
    surrounding notification (org.aopalliance.intercept.MethodInterceptor) is to implement enhancements before and after the execution of the target method , which can be applied to functions such as logging and transaction processing.
  2. Pre-notification
    Pre-notification (org.springframework.aop.MethodBeforeAdvice) is to implement enhancements before the execution of the target method , which can be applied to functions such as authority management.
  3. Post-return notification
    Post-return advice (org.springframework.aop.AfterReturningAdvice) is implemented after the successful execution of the target method and can be applied to functions such as closing the stream and deleting temporary files.
  4. Rear (final) notice
    after advice (org.springframework.aop.AfterAdvice) in the implementation of the enhanced target method execution , and post-return different notification, regardless of whether there should be an exception execution of the notice can be applied to release Resources .
  5. Exception notification
    Exception notification (org.springframework.aop.ThrowsAdvice) is to implement enhancements after the method throws an exception, and can be applied to functions such as exception handling and logging.
  6. Introduction notice The
    introduction notice (org.springframework.aop.IntroductionInterceptor) is to add some new methods and properties to the target class, which can be used to modify the target class (enhanced class).

There are two ways to implement Spring AOP using AspectJ:

  1. Development of AspectJ based on XML configuration
  2. Develop AspectJ based on annotations.

1. Develop AspectJ based on XML configuration

  Note: Developing AspectJ based on XML configuration refers to defining aspects, entry points and notifications through XML configuration files, all of which must be defined in the <aop:config>elements of applicationContext.xml .

Case realization

  1. pom.xml adds the dependency of AspectJ
<!--AspectJ 实现Spring AOP  方式:  1、aspectJ基于XML开发  切面编程AOP  事物回滚使用-->
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.5</version>
    </dependency>
  1. Create a proxy class (target class)
public interface UserDao {
    
    
    public void save();
    public void delete();
}
public class UserDaoImpl implements UserDao{
    
    
    @Override
    public void save() {
    
    
//        int i = 100/0;//测试异常抛出 虚拟机终止程序运行
        System.out.println("save user .....");
    }
    @Override
    public void delete() {
    
    
        System.out.println("delete user .....");
    }
}
  1. Create an aspect class
/*切面类中定义的一个个方法叫通知
 advice 通知 --- 是增强的方法,应用于被代理类方法的额外功能
 */

/*
 AspectJ中的切入点匹配的执行点称作连接的(JoinPoint),
在通知方法中可以声明一个JoinPoint类型的参数。通过JoinPoint可以访问连接点的细节
    1.java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
    2.Signature getSignature() :获取连接点的方法签名对象;
    3.java.lang.Object getTarget() :获取连接点所在的目标对象;
    4.java.lang.Object getThis() :获取代理对象本身;
    
    ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:
    5.java.lang.Object proceed() throws java.lang.Throwable:通过反射执行目标对象的连接点处的方法;
    6.java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通过反射执行目标对象连接点处的方法,不过使用新的参数替换原来的参数。
* */

public class MyAspect {
    
    
//    前置通知  advice
    public void before(JoinPoint joinPoint){
    
    
//        被代理对象
        joinPoint.getTarget();
//        目标对象被增强的方法

        //获取方法签名对象   public void save()  【除了{}方法体以外都是方法签名】
        joinPoint.getSignature().getName();
        System.out.println("前置通知,用于权限控制。。"+ joinPoint.getTarget()+" ----methodName---"+joinPoint.getSignature().getName());
    }

    //后置通知
    public void afterReturning(JoinPoint joinPoint){
    
    
        System.out.println("后置通知,清除操作过的文件"+ joinPoint.getTarget()+" ----methodName---"+joinPoint.getSignature().getName());
    }
//  环绕通知 ProceedingJoinPoint是joinPoint的子类
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        System.out.println("环绕通知,方法执行之前,开启事务");
        joinPoint.proceed();  //让方法继续执行
        System.out.println("环绕通知,方法执行之后,关闭事务");
    }

    public void afterThrowing(Throwable e) throws Throwable {
    
    

        System.out.println("异常通知:方法出现异常调用,处理异常"+e.getMessage());

    }

    public void after(JoinPoint joinPoint) {
    
    
        System.out.println("最终通知  管理数据库连接等清理工作");

    }
}
  1. Create configuration file applicationContext.xml and write related configuration
<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">

    <!-- 被代理类 目标类 -->
    <bean id="userDao" class="com.xgf.aop.aspectj.xml.UserDaoImpl"/>

    <!--切面类  干什么事情-->
    <bean id="myAspect" class="com.xgf.aop.aspectj.xml.MyAspect"/>

    <!-- 基于XML配置开发AspectJ是指通过XML配置文件定义切面、切入点及通知,所
            有这些定义都必须在<aop:config>元素内。【***】 -->
    <aop:config>
        <!--引入切面类  -->
        <aop:aspect ref="myAspect">
            <!-- 执行的方法  在什么地方   pointcut切点
               execution(返回值类型 包名.类名.方法名(参数))
                (..)代表任意参数
            -->
            <aop:pointcut id="mycut" expression="execution(* com.xgf.aop.aspectj.xml.*.*(..))"/>

         <!-- 切入时机 -->
            <!--前置通知  方法执行之前-->
            <aop:before method="before" pointcut-ref="mycut"/>

            <!--后置返回通知 方法执行之后执行,方法正常结束才调用,出现异常不会调用-->
            <aop:after-returning method="afterReturning" pointcut-ref="mycut"/>

            <!--环绕通知  -->
            <aop:around method="around" pointcut-ref="mycut"/>

            <!--异常通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="mycut" throwing="e"/>

            <!-- 最终(后置)通知 不管方法是否出现异常都会执行,进行资源释放等清理工作 -->
            <aop:after method="after" pointcut-ref="mycut"/>
        </aop:aspect>
    </aop:config>
</beans>
  1. Write test class
public class AspectJXMLTest {
    public static void main(String[] args) {

        ApplicationContext context =
                new ClassPathXmlApplicationContext("com/xgf/aop/aspectj/xml/applicationContext.xml");

        /* 代理类 */
        UserDao userDao = (UserDao) context.getBean("userDao");
        userDao.save();
        userDao.delete();
    }
}
  1. operation result
    Insert picture description here



2. Develop AspectJ based on annotations [***]

  Note: It must be configured in applicationContext.xml <aop:aspectj-autoproxy></aop:aspectj-autoproxy>to make aop work.

AspectJ notification comment [***]

Annotation name Described above
@Aspect Used to define an aspect , the annotation is on the aspect class
@Pointcut Used to define the pointcut expression . In use, you need to define an entry point method. This method is an ordinary method with a return value of void and an empty method body
@Before Used to define pre-notification . When using, usually specify the value attribute value for it, the value can be an existing pointcut, or directly define the pointcut expression
@AfterReturning It is used to define the rear return notification . When using, usually specify the value attribute value for it, the value can be an existing pointcut, or directly define the pointcut expression
@Around It is used to define around advice . When using, usually specify the value attribute value for it, the value can be an existing pointcut, or directly define the pointcut expression
@AfterThrowing Used to define exception notifications . When in use, it is usually assigned a value attribute value, which can be an existing pointcut or directly define a pointcut expression. In addition, there is a throwing attribute used to access the exception thrown by the target method. The value of this attribute is consistent with the formal parameter of the same name in the exception notification method.
@After Used to define post (final) notifications . When using, usually specify the value attribute value for it, the value can be an existing pointcut, or directly define the pointcut expression

Connection point (JoinPoint)【***】

Some time points in the running of the program, such as the execution of a method, or the handling of an exception (the front and back of the method are all connection points)

JoinPoint object method description
Signature getSignature() Get the object that encapsulates the signature information, in which you can get the target method name, the Class of the class and other information
Object getTarget() Get the object being proxied
Object getThis() Get proxy object
Object[] getArgs() Get the parameter object passed into the target method (input parameter list)
joinpoint.proceed() Used in the surround notification around, used to start the execution of the target method (surround notification = front + target method execution + post notification)
joinPoint.getSignature().getName() Enhanced method for obtaining target objects

Case

  1. pom.xml import dependency
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.5</version>
    </dependency>
  1. Create a proxy class
public interface UserDao {
    
    
    public void save();
    public void delete();
}
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    
    
    @Override
    public void save() {
    
    
        //int i = 100/0;//异常抛出 虚拟机终止程序运行
        System.out.println("save 保存 ......");
    }
    @Override
    public void delete() {
    
    
        System.out.println("delete 删除 ......");
    }
}
  1. Create an aspect class
// @Component配置 启动容器会实例化类 名字首字母小写myAspect
// @Aspect配置切面
@Aspect
@Component
public class MyAspect {
    
    
    /* 配置切点 - pointcut切点
         execution(返回值类型 包名.类名.方法名(参数))
         (..)代表任意参数
    */
    @Pointcut("execution(* com.xgf.aop.aspectj.annotation.*.*(..))")

    public void mycut(){
    
    // 切点的id
    }

//    通知  advice
    //@Before("mycut()")    //当有多个值时用value  只有一个属性的时候直接写
    @Before(value="mycut()")
    public void before(JoinPoint joinPoint){
    
    
        //JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.

//        获取被代理对象
        joinPoint.getTarget();
//        目标对象被增强的方法
        joinPoint.getSignature().getName();
        System.out.println("前置通知,用于权限控制  被代理对象: "+ joinPoint.getTarget()+" ----方法名methodName---"+joinPoint.getSignature().getName());
    }

    @AfterReturning("mycut()")
    public void afterReturning(JoinPoint joinPoint){
    
    
        System.out.println("后置返回通知,清除操作过的文件  被代理对象:"+ joinPoint.getTarget()+" ----方法名methodName---"+joinPoint.getSignature().getName());
    }

    @Around("mycut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        System.out.println("环绕通知,方法执行之前,开启事务");
        joinPoint.proceed();//启动目标方法执行
        System.out.println("环绕通知,方法执行之后,关闭事务");
    }

    @AfterThrowing(value = "mycut()",throwing = "e")
    public void afterThrowing(Throwable e) throws Throwable {
    
    
        System.out.println("异常通知:方法出现异常调用,处理异常"+e.getMessage());
    }

    @After("mycut()")
    public void after(JoinPoint joinPoint) {
    
    
        System.out.println("最终通知  管理数据库连接等清理工作");
    }
}
  1. To create the applicationContext.xml configuration file, you
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>must be certain, otherwise it won't work!
<?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:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--基于注解开发  扫描包-->
    <!-- 容器启动的时候 加载配置文件xml 读取com.xgf.aop.aspectj.annotation包识别注解 -->
    <context:component-scan base-package="com.xgf.aop.aspectj.annotation"/>

    <!--使aop起作用-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
  1. Write test class
public class AspectJAnnotationTest {
    
    
    public static void main(String[] args) {
    
    

        ApplicationContext context =
                new ClassPathXmlApplicationContext("com/xgf/aop/aspectj/annotation/applicationContext.xml");
        
        UserDao userDao = (UserDao) context.getBean("userDao");
        //调用方法
        userDao.save();
        userDao.delete();
    }
}
  1. Results of the
    Insert picture description here

Guess you like

Origin blog.csdn.net/qq_40542534/article/details/108684941