欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

AOP之基于XML的声明式AspectJ和注解式AspectJ的实现

程序员文章站 2022-07-12 14:09:47
...

springAop简介

什么是AOP?

# AOP全称是(Aspect-Oriented Programming),即 面向切面编程。它是 面向对象编程(OOP)的一种补充。

为什么要学习AOP?

# 可以想象一下,一个简单的程序的实现,可以看做是 自顶向上的一个实现,它是从主函数入口进入到实现某一个功能,要是给 这个程序 增加或者 改变 它的方法,就意味着我们要 去添加,修改,导致我们找不到  最核心的类。学习AOP,就是学习一种思想,把需要修改或者改变的方法单独拿出来,只需要在 需要的地方进行插入,这样能够保存 代码的独立性,简洁性,可以提高开发效率。

代理类AOP的实现

# Spring中默认就是使用JDK动态代理的方式来实现的。通过这个例子,可以清楚看到
//这是一个接口类
public interface UserDao {
    public void addUser();
    public void deleteUser();

}
//目标类:这个我们需要增强的方法,在它实现 添加和删除功能前后进行检查和记录
public class UserDaoImpl implements UserDao {
    public void addUser(){
        System.out.println("用户添加了...");
    }
    public void deleteUser(){
        System.out.println("用户删除了...");
    }
}
//切面类:在此类中编写 增强的advice,也就是通知,这里就是 增强的方法,把它放到 目标类前后
public class MyAspect {
    //前置通知
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("前置通知:模拟执行权限检查...");
        System.out.println("目标类: " + joinPoint.getTarget());
        System.out.println("被植入增强处理的目标方法" + joinPoint.getSignature().getName());
    }

    //后置通知
    public void myAfterReturning(JoinPoint joinPoint) {
        System.out.println("后置通知:模拟记录日志...");
        System.out.println("被植入增强处理的目标方法: " + joinPoint.getSignature().getName());
    }
    /*
    * 环绕通知
    *
    * */

    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //开始
        System.out.println("环绕开始: 执行目标方法之前,模拟开启事务...");
        //执行当前目标方法
        Object obj = proceedingJoinPoint.proceed();
        //结束
        System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
        return obj;
    }

    //异常通知
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常通知:" + "出错了..." + e.getMessage());
    }
    //最终通知
    public  void myAfter(){
        System.out.println("最终通知: 模拟方法结束后释放资源...");
    }
}
//在配置文件中把需要的bean加进去,方便可以配置
<?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 目标类: 需要增强的类
				id:表示创建一个 id为userDao的实例
				class:用于指定 需要实例化的 类
	-->
    <bean id="userDao" class="com.lbh.dao.UserDaoImpl"/>
    <!--2 切面
		同理,id就相当于起了一个别名,可以方便我们使用,我的理解是这样。
	-->
    <bean id="myAspect" class="com.lbh.AspectJ.MyAspect"/>
    <!--3 aop 切面--> //这里的知识我就不在写上面了,自己可以查找资料,
    <aop:config>
        <!--配置切面
			通常会指定 id和ref属性,
			id:用于定义 该切面的唯一标识名称
			ref: 用于引用普通的spring bean
		-->
        <aop:aspect ref="myAspect">
            <!--3.1 配置切入点,通知最后增强哪些方法-->
            <aop:pointcut expression="execution(* com.lbh.dao.*.*(..))" id="myPointCut"/>
            <!--3.2 关联通知advice和切入点-->
            <!--3.2.1 前置通知-->
            <aop:before method="myBefore" pointcut-ref="myPointCut"/>
            <!--3.2.2后置通知,在方法返回之后执行,就可以获得返回值
                    returning 属性:用于设置后置通知的第二个参数的名称,类型是object-->
            <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut"/>
            <!--3.2.3环绕通知-->
            <aop:around method="myAround" pointcut-ref="myPointCut"/>
            <!--3.2.4 抛出通知:用于处理程序发生异常-->
            <!--* 注意:如果程序没有异常,将不会执行增强-->
            <!--*        Throwing属性:用于设置通知第二个参数的名称,类型是Thronwable-->
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
            <!--3.2.5 最终通知:无论程序发生什么事情,都将执行-->
            <aop:after method="myAfter" pointcut-ref="myPointCut"/>
        </aop:aspect>
    </aop:config>

</beans>
//测试类,在这里可以测试结果
package com.lbh.AspectJ;

import com.lbh.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXmlAspectJ {
    public static void main(String[] args){
        String xml="applicationContext.xml";
        ApplicationContext applicationContext= new ClassPathXmlApplicationContext(xml);
        //1 从容器中获取内容
        UserDao userDao= (UserDao) applicationContext.getBean("userDao");
        //2执行方法
        userDao.addUser();
        userDao.deleteUser();
    }
}

结果如下:

AOP之基于XML的声明式AspectJ和注解式AspectJ的实现这就是一个 基于代理类的AOP实现.

接下来是一个 基于注解的声明式AspectJ

还是老样子,先放代码

//这还是一个接口类
package com.lbh.dao;

public interface UserDao {
    public void addUser();
    public void deleteUser();

}
package com.lbh.dao;

import org.springframework.stereotype.Repository;

//目标类:需要增强的方法
@Repository("userDao") //可以看到这里 有一个注解,
public class UserDaoImpl implements UserDao {
    public void addUser(){
        System.out.println("用户添加了...");
    }
    public void deleteUser(){
        System.out.println("用户删除了...");
    }
}

package com.lbh.AspectJs.annotatin;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/*
    切面类:在此类中编写 增强的advice,也就是通知
*/
//与前面不同的是,在切面类加了很多注解,
@Aspect
@Component
public class MyAspect {
    //定义切入点表达式
    @Pointcut("execution(* com.lbh.dao.*.*(..))")
    //使用一个空的返回值为void,方法体为空的方法来命名切入点
    private void myPointCut(){}
    //前置通知
    @Before("myPointCut()")
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("前置通知:模拟执行权限检查...");
        System.out.println("目标类: " + joinPoint.getTarget());
        System.out.println("被植入增强处理的目标方法" + joinPoint.getSignature().getName());
    }

    //后置通知
    @AfterReturning("myPointCut()")
    public void myAfterReturning(JoinPoint joinPoint) {
        System.out.println("后置通知:模拟记录日志...");
        System.out.println("被植入增强处理的目标方法: " + joinPoint.getSignature().getName());
    }
    /*
    * 环绕通知
    *
    * */
    @Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //开始
        System.out.println("环绕开始: 执行目标方法之前,模拟开启事务...");
        //执行当前目标方法
        Object obj = proceedingJoinPoint.proceed();
        //结束
        System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
        return obj;
    }

    //异常通知
    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
        System.out.println("异常通知:" + "出错了..." + e.getMessage());
    }
    //最终通知
    @After("myPointCut()")
    public  void myAfter(){
        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"
       xmlns:context="http://www.springframework.org/schema/context"
       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
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd"


>	
	//可以看到配置文件
    <!--1 指定需要扫描的包-->
    <context:component-scan base-package="com.lbh"/>
    <!--2 启动基于注解的声明式AspectJ支持-->
    <aop:aspectj-autoproxy/>
</beans>

```java
//测试类,可以看到结果。
package com.lbh.AspectJs.annotatin;

import com.lbh.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAnnotation {
    public static void main(String[] args){
        String xml= "applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xml);
        UserDao userDao= (UserDao) applicationContext.getBean("userDao");
        userDao.addUser();
        userDao.deleteUser();


    }
}

AOP之基于XML的声明式AspectJ和注解式AspectJ的实现






上一篇: AOP

下一篇: Intellij IDEA常用插件