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实现.
接下来是一个 基于注解的声明式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
下一篇: Intellij IDEA常用插件