Spring第二弹AOP

    技术2022-07-16  76

    注:本文章仅用于笔记,不做技术交流。如有繆误,敬请指出,(B站尚硅谷王泽老师笔记整理)

    概念

    切面编程,业务逻辑分离,降低业务逻辑耦合度 通俗讲就是,不修改源代码,但是在主干里面添加新功能

    术语

    1.连接点: 类里面可以被增强的方法称为连接点 2.切入点: 实际被增强的方法 3.通知: 1.实际增强的逻辑部分 2.多种类型: 前置通知 @before //增强之前 后置通知 @AfterReturning //增强之后 环绕异常 @Around //增强之前和之后 异常通知 @AfterThrowing //增强出现异常 最终通知 @After //try catch 的finally proceedingJoinPoint.proceed(); 是环绕通知中执行增强的方法,区分环绕之前和之后 出现异常的时候环绕之后(around注解的方法)和AfterReturning不执行 after一定通知try catch 的finally 4.切面: 把通知应用到切入点的过程

    AOP第一个情况有接口,使用JDK动态代理

    (1)调用 newProxyInstance 方法

    方法有三个参数: 第一参数,类加载器 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口 第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

    就是newProxyInstance()里面的方法参数

    public interface UserDao { public int add(int a,int b); public String update(String id); } public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } } public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1, 2); System.out.println("result:"+result); } } //创建代理对象代码 class UserDaoProxy implements InvocationHandler { //1 把创建的是谁的代理对象,把谁传递过来 //有参数构造传递 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 res = method.invoke(obj, args); //方法之后 System.out.println("方法之后执行...."+obj); return res; } }

    这个里面就可以看到在method.invoke()对method.getName()进行判断,做相应的方法处理 spring里面对相应的代码进行封装

    AOP第二个情况没有接口,使用CGLIB动态代理

    AspectJ

    4、切入点表达式

    (1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强 (2)语法结构: execution([权限修饰符] [返回类型] [类全路径] 方法名称 ) 举例 1:对包名字 类里面的 add 进行增强 execution(* 包名.方法(…)) 举例 2:对包名字 类里面的所有的方法进行增强 execution(* 包名.* (…))

    (1)在 spring 配置文件中,开启注解扫描 xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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"> //开启注解扫描 <context:component-scan basepackage="包名路径"></context:component-scan> (2)使用注解创建 User 和 UserProxy 对象 在这两个类对象的类上面添加@Component注解 (3)在增强类上面添加注解 @Aspect即UserProxy上面 (被增强类是User)(增强类是UserProxy ) 对有@Aspect注解生成代理对象 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    4、配置不同类型的通知

    (1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置 public class UserProxy { //前置通知 //@Before 注解表示作为前置通知 @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void before() { System.out.println("before........."); } //后置通知(返回通知) @AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void afterReturning() { System.out.println("afterReturning........."); } //最终通知 @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void after() { System.out.println("after........."); } //异常通知 @AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing........."); } //环绕通知 @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前........."); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后........."); } } 前置通知: 在执行需要增强的方法之前先执行before方法 其他通知均是在相应位置执行相应方法

    5、相同的切入点抽取

    //value里面写的是相应的切入点表达式(知道对哪个类里面的哪个方法进行增强), //在通知的注解里面对这个切入点表达式用 (value="函数名字") 进行调用 @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void pointdemo() { } //前置通知 //@Before 注解表示作为前置通知 @Before(value = "pointdemo()") public void before() { System.out.println("before........."); }

    6、有多个增强类多同一个方法进行增强,设置增强类优先级

    (1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高 @Component @Aspect @Order(1) public class PersonProxy

    7.(AspectJ 配置文件)

    <aop:config> <!--切入点--> <aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/> <!--配置切面--> <aop:aspect ref="bookProxy"> <!--增强作用在具体的方法上--> <aop:before method="before" pointcut-ref="p"/> </aop:aspect> </aop:config>

    8、完全使用注解开发

    (1)创建配置类,不需要创建 xml 配置文件 @Configuration @ComponentScan(basePackages = {“包名字”}) @EnableAspectJAutoProxy(proxyTargetClass = true) public class ConfigAop { }

    总结:

    AOP主要是在不改变原来的代码的基础上加入新的功能,主要是动态代理,区分有接口和没有接口的情况 有接口就使用JDK的动态代理 没有接口就使用AspectJ

    Processed: 0.009, SQL: 9