spring aop代理模式深入学习

spring AOP 面向切面编程 Aspect Oriented Programming(适用于权限检查,日志记录,性能分析,事务管理,异常管理) 。

AOP有三种织入切面的方法:

其一是编译期织入,这要求使用特殊的Java编译器,AspectJ是其中的代表者;
其二是类装载期织入,而这要求使用特殊的类装载器,AspectJ和AspectWerkz是其中的代表者;
其三为动态代理织入,在运行期为目标类添加增强生成子类的方式,Spring AOP采用动态代理织入切面。
Spring AOP使用了两种代理机制,一种是基于JDK的动态代理,另一种是基于CGLib的动态代理,之所以需要两种代理机制,很大程度上是因为JDK本身只提供基于接口的代理,不支持类的代理。

基于JDK的代理和基于CGLib的代理是Spring AOP的核心实现技术,认识这两代理技术,有助于探究Spring AOP的实现机理。只要你愿意,你甚至可以抛开Spring,提供自己的AOP实现。

实现aop 有两种方式:

  1. jdk动态代理
  2. cglib 动态代理

jdk动态代理

jdk 动态代理必须具备四个条件:
目标接口,目标类,拦截器(处理器),代理类
1.利用jdkProxy 生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有
2.生成的代理类的所有方法都拦截了目标类的所有的方法,而拦截器中的invoke方法的内容就是代理类的各个方法的组合体。
3.利用jdkProxy方式必须有接口的存在。
4.invoke方法中的三个参数
(Object proxy, Method method, Object[] args)
可以访问目标类的被调用方法的api,被调用犯法的参数,被调用方法的返回类型。

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author WangCong
 * @since 2020-04-30
 */
public interface SysUserLogService extends IService<SysUserLog> {

    int addLog(SysUserLog sysUserLog);
    String delLog(String userName);
}

实现类

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author WangCong
 * @since 2020-04-30
 */
@Service
public class SysUserLogServiceImpl extends ServiceImpl<SysUserLogMapper, SysUserLog> implements SysUserLogService {

    @Autowired
    private SysUserLogMapper sysUserLogMapper;
    @Override
    @Transactional
    public int addLog(SysUserLog sysUserLog) {
        return sysUserLogMapper.addLog(sysUserLog);
    }

    @Override
    public String delLog(String userName) {
        System.out.println(userName);
        return "删除成功";
    }
}

代理类

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

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : WangCong
 * @create 2020/5/6 10:35
 */
public class MyJDKProxy implements InvocationHandler {
    //需要被代理的目标对象
    private Object proxyObject;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("========JDK动态代理,监听开始!========");
        Object result = method.invoke(proxyObject, args);
        System.out.println("========JDK动态代理,监听结束!========");
        return result;
    }
    private Object getProxyInstance(Object targetObject) {
        //为目标对象target赋值
        this.proxyObject = targetObject;
        //JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader()
                , targetObject.getClass().getInterfaces(), this);
    }

    public static void main(String[] args) {
        //实例化JDKProxy对象
        MyJDKProxy myJDKProxy = new MyJDKProxy();
        //获取代理对象
        SysUserLogService userService = (SysUserLogService)myJDKProxy.getProxyInstance(new SysUserLogServiceImpl());
        userService.delLog("asdasdas");
    }
}

执行输出
在这里插入图片描述

cglib 动态代理

重点:jdk动态代理只能为接口创建代理。
而cglib动态代理是给没有接口的业务类使用的。
1.cglib 是一个很强大的code 生成类库,具有在运行期扩展java类与实现java接口的。
2. cglib 可以生成代理类是目标类的子类
3. 使用cglib不需要代理类实现接口
4. cglib的代理类会重写父类的各个方法
5. 拦截器中等intercept方法内容就是代理类中的方法体

cglib 代理类

import com.zk.zkapi.service.impl.SysUserLogServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : WangCong
 * @create 2020/5/6 10:39
 */
public class CglibProxy implements MethodInterceptor {
    private Object proxyObject;
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("==========CGlib动态代理,监听开始!==========");
        Object result = method.invoke(proxyObject, objects);
        System.out.println("==========CGlib动态代理,监听结束!==========");
        return result;
    }
    private Object getCglibProxy(Object objectTarget){
        this.proxyObject = objectTarget;
        Enhancer enhancer = new Enhancer();
        //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
        enhancer.setSuperclass(objectTarget.getClass());
        enhancer.setCallback(this);// 设置回调

        return enhancer.create();//创建并返回代理对象
    }

    public static void main(String[] args) {
        //实例化CglibProxy对象
        CglibProxy cglib = new CglibProxy();
        //获取代理对象
        SysUserLogServiceImpl agentService =  (SysUserLogServiceImpl) cglib.getCglibProxy(new SysUserLogServiceImpl());
        agentService.delLog("嘻嘻");

    }

运行中
在这里插入图片描述

总结

spring aop在底层是利用jdk动态代理或cglib动态代理为目标实体类植入横切逻辑。
spring aop 通过切点指定在那个类的那些方法上横切逻辑
通过 增强 描述横切逻辑和方法的具体植入点。
还通过切面 组合 切点和增强,有了切面的信息,spring就可以 利用jdk动态代理或cglib动态代理 来目标实体类创建植入的切面的代理对象了。
对于单例的代理对象或者具有实例池的代理,不需要频繁的创建代理对象,比较适合用cglib动态代理。
对于不是单例的对象,就可以用jdk 动态代理。此外由于cglib采用生成子类的方式创建代理对象,所以不能对目标类中的final修饰的方法进行代理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值