Day56-AOP

Day56_Spring_AOP

 

AOP(概念)

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

 

CGLIB动态代理的实现关键:

1.实现MethodInterceptor 的接口

2.给要被代理的对象创建一个代理对象

过程就是利用工具类获取要代理的对象的父类,再回调函数,最后创建子类(代理对象);

子类 == 代理对象

父类 == 要被代理的对象

/**
* Cglib子类代理工厂
* 对UserDao在内存中动态构建一个子类对象
*/
public class ProxyFactory implements MethodInterceptor{
   //维护目标对象
   private Object target;

   public ProxyFactory(Object target) {
       this.target = target;
  }

   //给目标对象创建一个代理对象
   public Object getProxyInstance(){
       //1.工具类
       Enhancer en = new Enhancer();
       //2.设置父类
       en.setSuperclass(target.getClass());
       //3.设置回调函数
       en.setCallback(this);
       //4.创建子类(代理对象)
       return en.create();

  }

   @Override
   public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
       System.out.println("开始事务...");

       //执行目标对象的方法
       Object returnValue = method.invoke(target, args);

       System.out.println("提交事务...");

       return returnValue;
  }
}

 

AOP(JDK 动态代理)(带接口的)

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

(1)调用 newProxyInstance 方法

方法有三个参数:

第一参数,类加载器

第二参数,增强方法所在的类,这个类实现的接口,支持多个接口

第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

 

AOP术语

1、连接点(Join point):类里面哪些方法可以被增强,这些方法称为连接点。(理论可以被增强,就叫连接点)

2、切入点(Pointcut):实际被真正增强的方法,称为切入点。(实际被增强的叫切入点)

3、通知(增强)(Advice):

(1)实际增强的逻辑称为通知(增强)

(2)通知有多种类型:

前置通知

后置通知

环绕通知

异常通知

最终通知

4、切面(Aspect)

是一个动作,把通知应用到切入点的过程。

 

 

AOP 操作(准备工作)

1、Spring 框架一般都是基于 AspectJ 实现 AOP 操作

(1)AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使 用,进行 AOP 操作

2、基于 AspectJ 实现 AOP 操作

(1)基于 xml 配置文件实现

(2)基于注解方式实现(一般都用这个)

3、在项目工程里面引入 AOP 相关依赖

 

4、切入点表达式 (1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强

(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]( [参数列表] ))

权限修饰符可以省略 (public 、private )(可以省略)(默认是public)

返回类型 (* - ->>返回任意类型的值或者不返回值。)(必填项)

对所有方法进行增强,用 —> * <——

对所有类和所有方法进行增强,用 —— > * .* <——

举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强

execution(* com.atguigu.dao.BookDao.add(..))

举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强

execution(* com.atguigu.dao.BookDao.* (..))

举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强

execution(* com.atguigu.dao . * . * (..))

 

AOP 操作(AspectJ 注解)

1.生成类,创建被增强类,在里面定义方法

2.创建增强类,在里面创建方法,让不同的方法代表不同的通知类型。

3.编写配置文件

    1. xmlns:context 
2. xmlns:aop
3. 在被增强类上加@Component。 和@Apsect

在增强类上加@Component

4. 开启注解扫描

<context:component-scan base—package = " com.sorrymaker.spring5.aop"></context:component-scan>

5.开启Apsect生成代理对象

<aop:aspectj -autoproxy></aop:aspect-autoproxy>

4.配置不同类型的通知。

在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

5、相同的切入点抽取 //相同切入点抽取 @Pointcut(value = "execution(* com.sorrymaker.spring5.aop.User.add(..))")

 

package com.sorrymaker.spring5.aop;

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

/**
* @Author nextGame
* @Date 2021/5/24 14:39
* @Version 1.0
* 增强类,
*/
@Aspect
@Component
public class UserProxy {

   @Pointcut(value = "execution(* com.sorrymaker.spring5.aop.User.add(..))")
   public void pointDemo(){

  }

   //前置通知
   //@before注解表示作为前置通知。
   @Before(value = "pointDemo()")
   public void before(){
       System.out.println("before.....");
  }

   //最终通知,不管有没有异常都执行
   @After(value = "pointDemo()")
   public void after(){
       System.out.println("after...");

  }

   //后置通知(返回通知) 异常就不执行了。
   @AfterReturning(value = "pointDemo()")
   public void afterReturning(){
       System.out.println("afterReturning...");

  }

   //异常通知,当被增强的方法异常,才会执行。
   @AfterThrowing(value = "pointDemo()")
   public void afterThrowing(){
       System.out.println("afterThrowing...");

  }

   //环绕通知
   @Around( value = "pointDemo()")
   public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
       System.out.println("环绕之前。。。。。");

       //被增强的方法执行。
       proceedingJoinPoint.proceed();

       System.out.println("环绕之后。。。。。");
  }
}

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

7、完全使用注解开发

创建配置类,不需要创建 xml 配置文件

@Configuration
@ComponentScan(basePackages = {"com.sorrymaker"})
//这里True是动态代理,false是cglib。
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}

AOP执行顺序

AOP执行顺序

AOP执行顺序增强版

 

 

AOP 操作(AspectJ 配置文件)

1、创建两个类,增强类和被增强类,创建方法

2、在 spring 配置文件中创建两个类对象

3、在 spring 配置文件中配置切入点

<!--创建对象-->
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean
   
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
<!--配置 aop 增强-->
<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>


 

小知识

方法的重写(override)两同两小一大原则

方法名相同,参数类型相同

子类返回类型小于等于父类方法返回类型,

子类抛出异常小于等于父类方法抛出异常,

子类访问权限大于等于父类方法访问权限。

 

synchronized 关键字 : 用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这个段代码。

volatile:用来确保将变量的跟新操作通知到其他线程,当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。然而,在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比 synchronized关键字更轻量级的同步机制。

serialize:Java 对象序列化为二进制文件。

static关键字: static关键字可以修饰变量,方法,静态代码块。

posted @ 2021-05-24 16:06  独眼龙  阅读(112)  评论(0)    收藏  举报