Spring(三)——AOP

打印 上一主题 下一主题

主题 868|帖子 868|积分 2604

Spring(三)——AOP

概念

什么是AOP

(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
AOP底层原理


  • JDK动态代理(有接口情况):创建接口实现类代理对象,增强类的方法
  • CGLIB动态代理(无接口情况):创建子类的代理对象,增强类的方法
JDK动态代理

1.使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

调用newProxyInstance 方法

  • 第一参数,类加载器
  • 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
  • 第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
2.编写JDK动态代理代码

(1)创建接口,定义方法
  1. package com.atguigu.spring5;
  2. public interface UserDao {
  3.     public int add(int a,int b);
  4.     public String update(String id);
  5. }
复制代码
(2)创建接口实现类,实现方法
  1. package com.atguigu.spring5;
  2. public class UserDaoImpl implements UserDao{
  3.     @Override
  4.     public int add(int a, int b) {
  5.         return a+b;
  6.     }
  7.     @Override
  8.     public String update(String id) {
  9.         return id;
  10.     }
  11. }
复制代码
(3)使用 Proxy 类创建接口代理对象
  1. package com.atguigu.spring5;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. import java.util.Arrays;
  6. public class JDKProxy {
  7.     public static void main(String[] args) {
  8.         //创建接口实现类代理对象
  9.         Class[] interfaces={UserDao.class};
  10. //                  方法一:
  11. //        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
  12. //            @Override
  13. //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  14. //<?xml version="1.0" encoding="UTF-8"?>
  15. <beans xmlns="http://www.springframework.org/schema/beans"
  16.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  17.        xmlns:context="http://www.springframework.org/schema/context"
  18.        xmlns:aop="http://www.springframework.org/schema/aop"
  19.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  20.                         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  21.                         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  22.    
  23.     <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
  24.    
  25.     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  26. </beans>return null;
  27. //            }
  28. //        });
  29.         UserDao userDao=new UserDaoImpl();
  30.         UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
  31.         int res=dao.add(1,2);
  32.         System.out.println(res);
  33.     }
  34. }
  35. //创建代理对象代码
  36. class UserDaoProxy implements InvocationHandler{
  37.     //创建谁的代理对象就把谁传进来
  38.     //有参构造传递
  39.     private Object obj;
  40.     public UserDaoProxy(Object obj){
  41.         this.obj=obj;
  42.     }
  43.     //增强逻辑
  44.     @Override
  45.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  46.         //方法之前
  47.         System.out.println("方法之前执行...."+method.getName()+" :传递的参 数..."+ Arrays.toString(args));
  48.         //被增强的方法执行
  49.         Object res = method.invoke(obj, args);
  50.         //方法之后
  51.         System.out.println("方法之后执行...."+obj);
  52.         return res;
  53.     }
  54. }
复制代码
AOP术语

1.连接点

类中哪些方法可以被增强,这些方法被称为连接点
2.切入点

实际被增强的方法叫切入点
3.通知(增强)

被增强的逻辑部分叫通知,下面是5种通知类型

  • 前置通知
  • 后置通知(返回通知)
  • 环绕通知
  • 异常通知
  • 最终通知
4.切面

是一个动作,把通知应用到切入点的过程
AOP操作-准备工作

Spring框架一般基于AspectJ实现AOP操作

AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,进行 AOP 操作
基于AspectJ实现AOP操作

(1)基于 xml 配置文件实现
(2)基于注解方式实现(使用)
引入AOP相关依赖

spring-aop-5.3.22.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.7.2.RELEASE.jar
切入点表达式

作用:知道对哪个类里面的哪个方法进行增强
语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]) )
举例1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
  1. //*表示任意修饰符public、private......(*后有空格)
  2. //..表示任意入参的方法
  3. execution(* com.atguigu.dao.BookDao.add(..))
复制代码
举例2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
  1. execution(* com.atguigu.dao.BookDao.* (..))
复制代码
举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
  1. execution(* com.atguigu.dao.*.* (..))
复制代码
AspectJ注解操作

1.创建类,在类里定义方法

2.创建增强类,编写增强逻辑

在增强类里面,创建方法,让不同方法代表不同通知类型
3.进行通知配置

(1)在 spring 配置文件中引入名称空间,开启注解扫描

(2)使用注解创建 User 和 UserProxy 对象

(3)在增强类上面添加注解 @Aspect,生成代理对象

(4)在 spring 配置文件中开启生成代理对象

4.配置不同类型的通知

在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
User.java
  1. package com.atguigu.spring5.aopanno;
  2. import org.aspectj.lang.annotation.Aspect;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. public class User {
  6.     public void add(){
  7.         System.out.println("User add..........");
  8.     }
  9. }
复制代码
UserProxy.java
  1. package com.atguigu.spring5.aopanno;
  2. import org.aspectj.lang.ProceedingJoinPoint;
  3. import org.aspectj.lang.annotation.*;
  4. import org.springframework.stereotype.Component;
  5. //增强类
  6. @Component
  7. @Aspect
  8. public class UserProxy {
  9.     //前置通知
  10.     //@Before 注解表示作为前置通知
  11.     @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
  12.     public void before() {
  13.         System.out.println("before.........");
  14.     }
  15.     //后置通知(返回通知)
  16.     @AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
  17.     public void afterReturning() {
  18.         System.out.println("afterReturning.........");
  19.     }
  20.     //最终通知
  21.     @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
  22.     public void after() {
  23.         System.out.println("after.........");
  24.     }
  25.     //异常通知
  26.     @AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
  27.     public void afterThrowing() {
  28.         System.out.println("afterThrowing.........");
  29.     }
  30.     //环绕通知
  31.     @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
  32.     public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  33.         System.out.println("环绕之前.........");
  34.         //被增强的方法执行
  35.         proceedingJoinPoint.proceed();
  36.         System.out.println("环绕之后.........");
  37.     }
  38. }
复制代码
TestAop.java
  1. package com.atguigu.spring5.test;
  2. import com.atguigu.spring5.aopanno.User;
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class TestAop {
  7.     @Test
  8.     public void testAopanno(){
  9.         ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
  10.         User user=context.getBean("user", User.class);
  11.         user.add();
  12.     }
  13. }
复制代码
bean1.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.        xmlns:context="http://www.springframework.org/schema/context"
  5.        xmlns:aop="http://www.springframework.org/schema/aop"
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7.                         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  8.                         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  9.    
  10.     <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
  11.    
  12.     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  13. </beans>
复制代码
5.相同切入点抽取

多个方法execution表达式相同时使用
  1. //相同切入点抽取
  2. @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
  3. public void pointdemo() {}
  4. @Before(value = "pointdemo()")
  5. public void before() {
  6.     System.out.println("before.........");
  7. }
复制代码
6.有多个增强类对同一个方法进行增强,设置增强类优先级先后执行

在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
7.完全注解开发

创建配置类
  1. @Configuration
  2. @ComponentScan(basePackages = {"com.atguigu"})
  3. @EnableAspectJAutoProxy(proxyTargetClass = true)
  4. public class ConfigAop {}
复制代码
配置文件操作

1、创建两个类,增强类和被增强类,创建方法
2、在spring配置文件中创建两个类对象
  1. [/code][b]3、在spring配置文件中配置切入点[/b]
  2. [code]<?xml version="1.0" encoding="UTF-8"?>
  3. <beans xmlns="http://www.springframework.org/schema/beans"
  4.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.        xmlns:context="http://www.springframework.org/schema/context"
  6.        xmlns:aop="http://www.springframework.org/schema/aop"
  7.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  8.                         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  9.                         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  10.    
  11.     <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
  12.    
  13.     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  14. </beans><?xml version="1.0" encoding="UTF-8"?>
  15. <beans xmlns="http://www.springframework.org/schema/beans"
  16.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  17.        xmlns:context="http://www.springframework.org/schema/context"
  18.        xmlns:aop="http://www.springframework.org/schema/aop"
  19.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  20.                         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  21.                         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  22.    
  23.     <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
  24.    
  25.     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  26. </beans>   
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

灌篮少年

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表