第6讲 | 谈谈Java反射机制,动态代理是基于什么原理?

谈谈Java反射机制,动态代理是基于什么原理?

反射机制

是Java语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。

通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。

动态代理

是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装RPC调用、面向切面的编程(AOP)。

实现动态代理的方式很多,比如JDK自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类
似ASM、 cglib(基于ASM)、 Javassist等。

JDK自身提供的动态代理 vs cglib(基于ASM)
JDK Proxy的优势:
  • 最小化依赖关系,减少依赖意味着简化开发和维护, JDK本身的支持,可能比cglib更加可靠。
  • 平滑进行JDK版本升级,而字节码类库通常需要进行更新以保证在新版Java上能够使用。
  • 代码实现简单
cglib框架的优势:
  • 有的时候调用目标可能不便实现额外接口,从某种角度看,限定调用者实现接口是有些侵入性的实践,类似cglib动态代理就没有这种限制。
  • 只操作我们关心的类,而不必为其他相关类增加工作量。
  • 高性能。

反射基本使用相关

获取class类实例方法:

Class clazz = String.class;
Class clazz = "abc".getClass();

Class cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass("类的全类名");

Class clazz = Class.forname("java.lang.String");

基本使用:

public class Person {
    private String name;
    private String age;

    public Person(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

demo

public class ReflectDemo {

    public static void main(String[] args) {
        String name = "reflect.Person";
        Class clazz = null;
        try {
            //1获取类对象
            clazz= Class.forName(name);
            //2.调用指定参数构造器
            Constructor con =  clazz.getConstructor(String.class,String.class);
            //3.通过Constructor的实例创建对应的类的对象,并且初始化类的属性
            Person p2 = (Person) con.newInstance("peter","20");
            System.out.println(p2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

打印:

Person{name='peter', age='20'}

还可以获取:
1.实现的全部接口:

public Class<?>[] getInterfaces() 

2.继承的父类

public native Class<? super T> getSuperclass();

3.全部的构造器

public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。

4.全部的方法

public Method[] getDeclaredMethods()
返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()
返回此Class对象所表示的类或接口的public的方法

5.全部的Field

public Field[] getFields()
返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields()
返回此Class对象所表示的类或接口的全部Field。
  1. Annotation相关
get Annotation(Class<T> annotationClass)
getDeclaredAnnotations()

7.泛型相关

获取父类泛型类型: Type getGenericSuperclass()
泛型类型: ParameterizedType
获取实际的泛型类型参数数组: getActualTypeArguments()

通过使用:

cons1.setAccessible(true);

setAccessible启动和禁用访问安全检查的开关
就能获取私有的(private)方法,变量等。

JDK代理

在这里插入图片描述

在这里插入图片描述

public interface UserService {
    void addUser();
    void updateUser();
}
public class UserServiceImpl implements UserService {

    public void addUser() {
        System.out.println("add user");
    }

    public void updateUser() {
        System.out.println("updateUser");
    }
}
public class MyAspect {
    public void before(){
        System.out.println("代理 before");
    }

    public void after(){
        System.out.println("代理 after");
    }
}

public class MyBeanFactory {
    public static UserService createService(){
        //1目标类
        final UserService userService = new UserServiceImpl();
        //切面类
        final MyAspect myAspect = new MyAspect();
        /**
         * 参数1: loader:类加载器,动态代理类,运行时创建,任何类都需要类加载器将其加载到内存。
         *         一般情况下:当前类.class.getClassLoader()
         *                   或者:    目标类.getClass().getClassLoader()
         * 参数2: Class[] interfaces 代理类需要实现的接口。
         *                   方式1:目标示例.getClass().getInterfaces(); 注意,只能获得自己的接口,不能获得父元素的接口
         *                   方式2: new Class[](UserService.class)
         *                   例如: jdbc驱动--》DriverManager 获得接口Connection
         *  参数3:
         *         InvocationHandler() 处理类,接口 必须进行实现类
         *         提供invoke方法:代理类的每一个方法执行的时候,都将执行一次invoke
         *          invoke方法中的参数:
         *                   3.1:Object proxy: 代理对象
         *                   3.2:Method method: 代理对象当前执行的方法描述对象(反射)
         *                          method.getName()
         *                          method.invoke(对象,实际参数)
         *                   3.3: Object[] args: 方法的实际参数
         */
        //动态代理
        UserService proxyService =
                (UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
                        userService.getClass().getInterfaces(),
                        new InvocationHandler() {
                            //将目标类和参数类结合
                            public Object invoke(Object proxy,
                                                 Method method,
                                                 Object[] args) throws Throwable {

                                myAspect.before();
                                Object obj = method.invoke(userService,args);
                                myAspect.after();
                                return obj;
                            }
                        });
        return proxyService;
    }
}

测试:

public class TestJdk {

    @Test
    public void demo1(){
        UserService userService = MyBeanFactory.createService();
        userService.addUser();
        userService.updateUser();
    }
}

在这里插入图片描述

Cglib代理

  • 没有接口,只有实现类
  • 采用字节码增强框架,在运行的时候创建目标子类,从而对目标类进行增强。

不需要service接口了

public class UserServiceImpl  {

    public void addUser() {
        System.out.println("add user");
    }

    public void updateUser() {
        System.out.println("updateUser");
    }
}
public class MyAspect {
    public void before(){
        System.out.println("代理 before");
    }

    public void after(){
        System.out.println("代理 after");
    }
}


public class MyBeanFactory {
    public static UserServiceImpl createService() {
        //1目标类
        final UserServiceImpl userService = new UserServiceImpl();
        //2切面类
        final MyAspect myAspect = new MyAspect();
        //3.代理类 创建目标类的子类
        //3.1 核心类
        Enhancer enhancer = new Enhancer();
        //3.2 确定父类
        enhancer.setSuperclass(userService.getClass());
        //3.3 设置回调函数,MethodIntercepter 接口等效jdk
        /**
         * 参数1 2 3 和 jdk invoke一样
         * 参数4:方法的代理
         */
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object proxy,
                                    Method method,
                                    Object[] args,
                                    MethodProxy methodProxy) throws Throwable {
                myAspect.before();
                Object object = method.invoke(userService, args);
                //执行代理类的父类,也就是执行目标类(目标类和代理类 父子关系)
               // methodProxy.invokeSuper(proxy,args);
                myAspect.after();
                return object;
            }
        });
        //创建代理
        UserServiceImpl proxyService = (UserServiceImpl) enhancer.create();

        return proxyService;
    }
}

测试类:

public class TestCglib {

    @Test
    public void demo1(){
        UserServiceImpl userService = MyBeanFactory.createService();
        userService.addUser();
        userService.updateUser();
    }
}

参考:
极客时间:《Java核心技术面试精讲》

本笔记根据专栏主题进行学习笔记,虽然参考了许多做了笔记,但是加上了自己的整理,跟原作者的内容可能有很大偏差。如果想查看原版请自行搜索。谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值