Spring中Aop的理解
Spring中的Aop
1、什么是AOP?
面向切面编程。利用它可以对业务逻辑的各个部分进行隔离,从而使得业务部分之间的耦合度降低,提高程序开发效率。
应用场景有:日志记录、性能统计、安全控制、事务处理、异常处理...
通俗描述:不通过修改源代码方式,在主干功能里添加新功能
AOP底层原理:
1、底层使用了动态代理
(1)有两种情况的动态代理
第一种:有接口,使用JDK动态代理
(1)调用newProxyInstance方法
方法三个参数:
第一:类加载器
第二:增强方法所在的类,这个类实现的接口,支持多个接口
第三:实现这个接口InvocationHandler,创建代理对象,写增强方法,示例代码如下:
public class ProxyJDK { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; /* Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } });*/ UserDaoImpl userDao=new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); dao.update(); } } //创建代理对象代码 class UserDaoProxy implements InvocationHandler { //创建的是谁的代理对象,把谁传过来,有参构造器 private Object obj; public UserDaoProxy(Object obj) { this.obj = obj; } //增强部分 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("开始增强" + method.getName() + ":传递的参数.." + Arrays.toString(args)); //被增强的方法执行 Object invoke = method.invoke(obj, args); //方法之后 System.out.println("执行结束" + obj); return null; } }
创建接口实现类代理对象,增强类的方法
第二种:没有接口情况,使用CGLIB动态代理
创建子类的代理对象,增强类的方法
AOP术语:
1、连接点:类里哪些方法可以被增强,这些方法称为切入点
2、切入点:实际被真正增强的方法
3、通知(增强):实际增强的逻辑部分
类型有:
前置通知:
后置通知:
环绕通知:
异常通知:
最终通知:
4、切面:是动作,把通知应用到切入点的过程
AOP操作:
1、一般基于AspectJ实现。
2、基于AspectJ实现AOP操作:
(1)基于xml配置文件
(2)基于注解方式(常用)
3、需要引入的依赖:
其中aspectj.weaver包用下面的包代替:
1 2 3 4 5 | <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version> 1.8 . 7 </version> </dependency> |
4、切入点表达式:
(1)作用:知道对哪个类里的哪个方法进行增强
(2):语法结构:
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
示例:对com.zhaojianhui.dao.Bookdao类里的add方法增强
execution(* com.zhaojianhui.dao.Bookdao.add(..))
示例:对com.zhaojianhui.dao.Bookdao类里的所有方法增强
execution(* com.zhaojianhui.dao.Bookdao.*(..))
示例:对com.zhaojianhui.dao包里所有类,类里的所有方法增强
execution(* com.zhaojianhui.dao.*.*(..))
AOP操作(注解方式)
1、创建类,在类中定义方法
1 2 3 4 5 | public class User { public void add(){ System.out.println( "add..." ); } } |
2、创建增强类(编写增强逻辑)
1 2 3 4 5 6 7 | //增强类 public class UserProxy { //前置通知 public void before(){ System.out.println( "before.." ); } } |
3、通知配置
(1)在spring配置文件中开启注解扫描
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?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:util= "http://www.springframework.org/schema/util" 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/util http: //www.springframework.org/schema/util/spring-util.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"><br> |
(2)使用注解创建User和UserProxy对象
(3)在增强类上加注解@Aspect
(4)在spring配置文件中开启生成代理对象
1 2 | <!--开启AspectJ代理生产对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> |
4、配置不同类型通知
@Component @Aspect //增强类 public class UserProxy { //前置通知 @Before("execution(* org.zhaojianhui.Spring.Bean.User.add(..))") public void before(){ System.out.println("before.."); } }
测试:
1 2 3 4 5 6 7 8 9 | public void test() { ApplicationContext appo = new ClassPathXmlApplicationContext( "bean2.xml" ); //ApplicationContext appo = new AnnotationConfigApplicationContext(SpringConfig.class);;//加载配置类 User user = appo.getBean( "user" , User. class ); user.add(); } } |
public class ProxyJDK {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
/* Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});*/
UserDaoImpl userDao=new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
dao.update();
}
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
//创建的是谁的代理对象,把谁传过来,有参构造器
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强部分
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("开始增强" + method.getName() + ":传递的参数.." + Arrays.toString(args));
//被增强的方法执行
Object invoke = method.invoke(obj, args);
//方法之后
System.out.println("执行结束" + obj);
return null;
}
}
相同切入点抽取:
//前置通知 @Before(value = "pointCutDemo()") public void before() { System.out.println("before.."); } //相同切入点抽取 @Pointcut(value = "execution(* org.zhaojianhui.Spring.Bean.User.add(..))") public void pointCutDemo() { }
有多个增强类对同一个方法进行增强,设置增强类优先级:在增强类上添加@Order(值)注解,值越小,优先级越高。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端