spring AOP 详解


为了面试,记录一下spring的基础

什么是IOC

IOC(控制反转):将由spring 创建对象实例

什么是DI

DI (依赖注入),类似于设计原则中依赖倒置
is a (是一个) : 泛化(继承)
has a(有一个) : 依赖
依赖:一个对象需要使用另一个对象
注入:通过setter 方法进行另一个对象的实例

private ADao a = new AImpl(); // 耦合
private ADao a; // 解耦,不知道实现对象,可以通过setter 方法注入

AOP

AOP 面向切面编程

AOP 实现原理

  • AOP 底层将采用代理机制进行实现。
  • 接口 + 实现类 : spring 采用jdk 的动态代理 Proxy
  • 实现类 : spring 采用 cglib 字节码的增强
    经典应用:事务管理性能检测,缓存

AOP 术语

target 目标类 ,需要被代理的类。 例如 UserService
JoinPoint(连接点):所谓连接点是指那些可能被拦截的方法。例如,所有的方法。
PointCut 切入点:已经被增强的连接点。例如 addUser()
advice 通知增强,例如 after , before
Weaving(织入):是指把增强advice应用到目标对象来创建新的代理对象的过程。
proxy:代理类
aspect(切面):是切入点pointcut和通知advice的结合

JDK 动态代理

通过jdk 动态代理实现 切面编程

// 目标类
public interface UserService {

    public void addUser();

    public void updateUser();

    public void deleteUser();
}
// 实现类 (所有方法)
public class UserServiceImpl implements UserService{

    @Override
    public void addUser() {
        System.out.println("addUser");
    }

    @Override
    public void updateUser() {
        System.out.println("updateUser");
    }

    @Override
    public void deleteUser() {
        System.out.println("deleteUser");
    }
}
// 切面
public class MyAspect {

    public void before(){
        System.out.println("before");
    }

    public void after(){
        System.out.println("after");
    }
}
package com.longchuang.aop;


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

public class MyBeanFactory {

    public static UserService create(){
        // 1,目标类
        UserService userService = new UserServiceImpl();
        // 2,切面类
        MyAspect myAspect = new MyAspect();
        // 3,代理类:将目标类和切面类(通知) 结合 --》 切面
        /**
         * Proxy.newProxyInstance()
         * 参数1: loader ,类加载器,动态代理运行时创建,任何类都需要类加载器将其加载到内存。
         *      一般情况:当前类.class.getClassLoader();
         *                  目标类.getClass.getCla...
         * 参数2:Class[] interfaces 代理类需要实现的所有接口
         *      方式1:目标类实例.getClass.getInterfaces(); // 注意:只能获得自己接口,不能获得父元素接口
         *      方式2:new Class[]{UserService.class}
         *
         * 参数3:InvocationHandler 处理类,接口,必须进行实现
         *          参数31:Object proxy : 代理对象
         *          参数32: Method method : 代理对象当前执行的方法描述对象(反射)
         *          参数33:Object[] args : 方法实际参数
         */
        UserService proxyService = (UserService)Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
                userService.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //前方法
                        myAspect.before();
                        // 执行目标方法
                        Object invoke = method.invoke(userService, args);
                        //后方法
                        myAspect.after();

                        return invoke;
                    }
                });


        return proxyService;
    }
}

cglib

  • 没有借口,只有实现类
  • 采用字节码增强框架,运行时, 创建目标类子类,从而对目标类进行增强
// 这里除去UserService借口类,还有就是此实现类不一致 
public class MyBeanFactory {

    public static UserServiceImpl create(){
        // 1,目标类
        UserServiceImpl userService = new UserServiceImpl();
        // 2,切面类
        MyAspect myAspect = new MyAspect();
        // 3,代理类:采用cglib ,底层创建目标的子类
        // 3.1 核心类
        Enhancer enhancer = new Enhancer();
        // 3.2 确认父类
        enhancer.setSuperclass(userService.getClass());
        /**
         * 3.3 设置回调函数,MethodInterceptor 接口等效jdk InvocationHandler 接口
         *   intercep() 等效jdk invoke()
         *      参数1、参数2、参数3 : 以invoke 一样
         *
         */
         enhancer.setCallback(new MethodInterceptor){

             @Override
             public Object intercep(Object proxy , Method method , Object[] args , MethodProxy proxyMethod){
                //前
                myAspect.before();
                // 执行目标类方法
                Object obj = method.invoke(userService,args);
                //后
                myAspect.after();
                return obj;
            }
        }
        
        UserServiceImpl proxyService = (UserServiceImpl)enhancer.create();

        return proxyService;
    }
}

aop 通知类型

spring 按照通知Advice 在目标方法的连接点位置,可以分为5类

  • 前置通知
  • 后置通知
  • 环绕通知
  • 抛出异常通知
  • 引介通知(很少用)

AspectJ 实现 AOP

切入点表达式 execution ( com.sample.service.impl…*. (…))

  • execution(): 表达式主体。
  • 第一个*号:表示返回类型, *号表示所有的类型。
  • 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
  • 第二个*号:表示类名,*号表示所有的类。
  • *(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数

AspectJ 通知类型

  • before 前置通知(应用于数据校验)
  • afterReturning 后置通知(常规数据处理)
  • around 环绕通知
  • afterThrowing 掏出异常通知
  • after 最终通知

实战

@Slf4j
@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* city.thesixsectorteam.wheelworld.area.controller.TestController1.*(..))")
    public void pointcut2(){
    }

    @Before("pointcut2()")
    public void tes2t(JoinPoint joinPoint){
        System.out.println("test");
    }

}

当我调用TestController1 中的接口时,就会打印 test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值