Spring5------------AOP

AOP(Aspect Oriented Programming):面向切面编程

作用:不改变源代码的情况下增强功能

AOP原理:动态代理

 

 

两种情况的动态代理

(1)有接口的情况,使用JDK动态代理

创建接口实现类代理对象,增强类的方法

 

 

(2)没有接口的情况:使用CGLIB动态代理

创建当前类子类的代理对象,增强类的方法

 

 

JDK动态代理

使用Proxy类里面的方法创建代理对象

 

调用newProxyInstance方法

 

 

 方法有三个参数:

  • 类加载器
  • 被代理类实现的接口(支持多个接口)
  • 调用处理器(实现InvocationHandler接口,创建代理对象,写增强方法)

 

package com.tang.spring;

public interface UserDao {
    int add(int a,int b);
    String update(String id);
}

  

package com.tang.spring;

import org.springframework.stereotype.Repository;

public class UserDaoImpl implements UserDao{

    @Override
    public int add(int a, int b) {
        System.out.println("add方法执行");
        return a+b;
    }

    @Override
    public String update(String id) {
        System.out.println("update方法执行");
        return id;
    }
}

  

package com.tang.spring;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
        //创建接口实现类代理对象
        UserDao userDao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(new UserDaoImpl()));
        int sum=userDao.add(2, 3);
        System.out.println("sum:"+sum);
    }
}

class UserDaoProxy implements InvocationHandler{

    private Object object;
    //把被代理对象传进来,这里的被代理对象是UserDao的实现类,即UserDaoImpl
    //通过有参构造方法传递进来
    public UserDaoProxy(Object object){
        this.object=object;
    }

    //增强的逻辑代码
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前
        System.out.println("方法之前执行————"+method.getName()+"————传递的参数:"+ Arrays.toString(args));

        //被增强的方法执行
        Object result=method.invoke(object, args);

        //方法之后
        System.out.println("方法执行之后————"+object);
        return result;
    }
}

  

 

AOP术语

(1)连接点:类里面可以被增强的方法称为连接点

(2)切入点:实际真正被增强的方法称为切入点

(3)通知(增强):实际增强的逻辑代码称为通知(增强)

  • 前置通知
  • 后置通知
  • 环绕通知
  • 异常通知
  • 最终通知

(4)切面:把通知(增强)应用到切入点 的过程

 

AspectJ

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

什么是AspectJ :AspectJ不是Spring组成部分,是一个独立的AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

 

引入依赖

 

 切入点表达式

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

语法结构:excution(访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表))

访问修饰符可省略,默认为public

表示当前包及其子包*..

..表示有无参数均可,有参数时可以是任意类型

1.最全的写法
拦截返回void,指定类的指定方法,参数必须有两个:int、String
execution(public void com.sunny.service.Impl.AccountServiceImpl.save(int,java.lang.String))
2.省略访问修饰符,返回值任意的指定类的save方法,无参数
execution(* com.sunny.service.Impl.AccountServiceImpl.save())
3.拦截com包下所有的类、以及其子包下所有的类的save()方法
execution(void com..*.save()) 包名与类名或方法名称都可以使用*
4.拦截save()方法/拦截所有方法
execution(* save()) 拦截save()
execution(* *()) 拦截所有方法
5.不拦截save()方法
!execution(* save())
not execution(* save()) 注意not前面要有空格
6.拦截save()方法或者update()方法
execution(* save()) || execution(* update()))
execution(* save()) or execution(* update()))
7.拦截所有方法,参数任意,但必须有参数
execution(* *(*))
8.拦截所有方法,参数任意,参数可有可无
execution(* *(..))
9.对IOC容器中以Service结尾的类,生成代理对象
bean(*Service)
10.最常用
execution(* com.sunny..*ServiceImpl.*(..))
表示com.sunny包及其子包下所有的以ServiceImpl结尾的类生成代理对象

 

 

基于xml配置文件实现

    <!--创建对象-->
    <bean id="user" class="javax.jws.soap.SOAPBinding$Use"></bean>
    <bean id="userProxy" class="com.tang.spring.UserProxy"></bean>

    <!--配置AOP增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* com.tang.spring.User.add(..))"/>
        <!--配置切面-->
        <aop:aspect ref="userProxy">
            <!--增强作用在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>
        </aop:aspect>
    </aop:config>

  

基于注解方式实现

通知的配置

第一步:在配置文件中开启注解扫描

第二步:使用注解创建对象

第三步:在增强类上添加@Aspect注解

第四步:在配置文件中开启生成代理对象

 

package com.tang.spring;

import org.springframework.stereotype.Component;

//被增强的类
@Component(value = "user")
public class User {
    public void add(){
        System.out.println("add..........");
    }
}

  

package com.tang.spring;

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

//增强的类
@Component
@Aspect     //生成代理对象
public class UserProxy {
    //通知顺序:环绕前——前置——AfterReturning——后置——环绕后

    //前置通知
    //@Before表示作为前置通知
    @Before(value = "execution(* com.tang.spring.User.add(..))")
    public void before(){
        System.out.println("before.........");
    }

    
    @After(value = "execution(* com.tang.spring.User.add(..))")
    public void after(){
        System.out.println("after..........");
    }

    @AfterReturning(value = "execution(* com.tang.spring.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning");
    }

    //异常通知
    @AfterThrowing(value = "execution(* com.tang.spring.User.add(..))")
    public void afterThrowing(){

    }

    //add方法执行之前和之后都会执行
    //环绕通知
    @Around(value = "execution(* com.tang.spring.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("before around");

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

        System.out.println("after around");
    }
}

  

相同切入点抽取

package com.tang.spring;

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

//增强的类
@Component
@Aspect     //生成代理对象
public class UserProxy {
    //通知顺序:环绕前——前置——AfterReturning——后置——环绕后

    //相同切入点抽取
    @Pointcut(value = "execution(* com.tang.spring.User.add(..))")
    public void point(){

    }

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

    //后置通知
    @After(value = "point()")
    public void after(){
        System.out.println("after..........");
    }

    @AfterReturning(value = "point()")
    public void afterReturning(){
        System.out.println("afterReturning");
    }

    //异常通知
    @AfterThrowing(value = "point()")
    public void afterThrowing(){

    }

    //add方法执行之前和之后都会执行
    //环绕通知
    @Around(value = "point()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("before around");

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

        System.out.println("after around");
    }
}

  

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

在增强类上面增加注解@Order(数字),数字从开始,数字越小优先级越高

例如:@Order(1) 优先级大于 @Order(2)

 

完全注解开发,创建配置类,不需要xml配置文件

package com.tang.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration   //指定当前类作为配置类,替代xml文件
@ComponentScan(basePackages = {"com.tang.spring"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class MyConfig {
}

  

 

posted @ 2021-04-03 11:24  455994206  阅读(106)  评论(0)    收藏  举报