欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringAop底层原理 Java动态代理思想

程序员文章站 2022-06-17 19:49:22
...

java动态代理实现与原理详细分析

关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式–代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。在后面我会

解释这种间接性带来的好处。代理模式结构图(图片来自《大话设计模式》):
SpringAop底层原理 Java动态代理思想
看这个是不是有点费劲,来下面我们来个简单的
SpringAop底层原理 Java动态代理思想
通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现) ,AOP核心技术面向切面编程。

代理模式运用场景

SpringAop ,事务原理,日志打印,权限控制,远程调用,安全代理

代理的分类

静态代理(静态定义代理类)
动态代理(动态生成代理类)
Jdk自带动态代理
Cglib 、javaassist(字节码操作库)

什么是静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

package com.evan.springboot.designStudy.proxyDemo;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 10:42
 */
public interface UserService {
    void save();
}


public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("插入用户成功");
    }
}


package com.evan.springboot.designStudy.proxyDemo.st;

import com.evan.springboot.designStudy.proxyDemo.UserService;
import com.evan.springboot.designStudy.proxyDemo.UserServiceImpl;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 10:45
 */
public class UserProxy implements UserService {
    private UserService userService;

    public UserProxy(UserService userService){
        this.userService=userService;
    }

    @Override
    public void save() {
        System.out.println("开启事务");
        userService.save();
        System.out.println("事务执行");
    }


    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserProxy userProxy = new UserProxy(userService);
        userProxy.save();
    }
}

SpringAop底层原理 Java动态代理思想

什么是动态代理

1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3.动态代理也叫做:JDK代理,接口代理

JDK动态代理

  • 原理:

根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口,面向接口生成代理,位于java.lang.reflect包下)

  • 实现方式
    1,通过实现InvocationHandler接口创建自己的调用处理器UserJDkProxy。
  1. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  2. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  3. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

缺点:jdk动态代理,必须是面向接口,目标业务类必须实现接口

package com.evan.springboot.designStudy.proxyDemo;

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

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 10:57
 */
public class UserJDkProxy implements InvocationHandler {
    private UserService userService;
    public UserJDkProxy(UserService userService){
        this.userService=userService;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk 动态代理开始");
        Object invoke = method.invoke(userService, args);
        System.out.println("Jdk 动态代理结束");
        return invoke;
    }
}

package com.evan.springboot.designStudy.proxyDemo;

import java.lang.reflect.Proxy;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 11:06
 */
public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserJDkProxy userJDkProxy = new UserJDkProxy(userService);
        UserService o = (UserService) Proxy.newProxyInstance(userJDkProxy.getClass().getClassLoader(), userService.getClass().getInterfaces(), userJDkProxy);
        o.save();
    }
}

SpringAop底层原理 Java动态代理思想

Cglib动态代理

  • 原理:

利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

什么是CGLIB动态代理

使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码

package com.evan.springboot.designStudy.proxyDemo;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

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

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 11:31
 */
public class UserCglibProxy implements MethodInterceptor {
    private Object object;
    public Object getInstance(Object object){
        this.object=object;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);
        Object o = enhancer.create();
        return o;

    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib 动态代理事务开始");
        Object invoke = methodProxy.invoke(object, objects);
        System.out.println("Cglib 动态代理事务结束");
        return invoke;
    }
}

package com.evan.springboot.designStudy.proxyDemo;

import java.lang.reflect.Proxy;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 11:06
 */
public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserJDkProxy userJDkProxy = new UserJDkProxy(userService);
        UserService o = (UserService) Proxy.newProxyInstance(userJDkProxy.getClass().getClassLoader(), userService.getClass().getInterfaces(), userJDkProxy);
        o.save();

        UserCglibProxy userCglibProxy = new UserCglibProxy();
        UserService instance = (UserService) userCglibProxy.getInstance(userService);
        instance.save();
    }
}

SpringAop底层原理 Java动态代理思想

CGlib动态代理和JDK动态代理的区别

java动态代理是利用反射机制生成一个实现代理接口的匿名内部类
cglib是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理

Spring中
1,如果目标对象实现了接口,默认情况下回采用JDK的动态代理实现AOP
2,如果目标对象实现了接口,可以强制使用CGlib实现AOP
3,如果目标没有实现接口,必须采用Cglib库,spring会自动在jdk动态代理和cglib之间转换

JDK动态代理只能对实现了接口的类型生成代理,而不能针对类
Cglib是针对类实现代理,主要是对指定类生成一个子类,覆盖其中方法。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。