一、前言
1、学习动态代理是一件很必要的事情,因为目前主流框架spring中的AOP底层其实就是通过“动态代理”而实现的,IOC是通过反射机制来获取到工厂对象这也是spring框架的核心两大块,当然IOC不在本文内容范畴
2、了解动态代理首先要明白它的作用、在哪使用,怎么用我觉得是很值得去想的一件事情,然后根据这种拆分我们一一的深入了解它
二、实战部分
1.首先定义一个Programmer接口类
package com.yushi.service;
/**
* 在Programmmer接口类定义两个方法
* @Date: 2019/7/26 14:52
*/
public interface Programmer {
void writerCode();
void fixBug(Integer num);
}
2.定义一个ProgrammerImpl类来实现接口方法
package com.yushi.impl;
import com.yushi.service.Programmer;
/**
* @Author: ****
* @Date: 2019/7/26 14:54
*/
public class ProgrammerImpl implements Programmer {
private Integer num;
@Override
public void writerCode() {
System.out.println("我是码农,我会写代码");
}
@Override
public void fixBug(Integer num) {
System.out.println("我是码农,每天要改"+num+"个bug");
}
}
3.通过main方法中来实现动态代理获取对象类过程
package com.yushi.client;
import com.yushi.impl.ProgrammerImpl;
import com.yushi.service.Programmer;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Author: ***
* @Date: 2019/7/21 11:39
*/
public class Client {
public static void main(String[] args) {
Programmer coder = (Programmer) Proxy.newProxyInstance(ProgrammerImpl.class.getClassLoader(),
ProgrammerImpl.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(ProgrammerImpl.class.newInstance(),args);
}
});
coder.fixBug(10);
}
}
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
动态代理角色:
- 代理类:接口类(Programmer)
- 被代理类:接口实现类(ProgrammerImpl)
动态代理核心部分:
- newProxyInstance方法返回的是一个object类型的对象,必须通过object类型变量接收,或被代理类实现的接口类型变量接收
System.out.println(coder); 打印返回的是ProgrammerImpl类型的实例化对象
- ClassLoader loader类加载器,需要将被代理类ProgrammerImpl通过类加载器动态加载到jvm内存中
- Class<?>[] interfaces返回的是被代理对象对应实现接口类的数组
//通过此方式打印的cls为接口类型名(interface com.yushi.service.Programmer)
Class[] classes = ProgrammerImpl.class.getInterfaces();
for (Class cls:classes){
System.out.println(cls);
}
- InvocationHandler 为接口类,通过invoke方法可以调用被代理对象的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
-
proxy变量一般不用到
-
method被代理类方法
-
args被代理类方法参数
1.通过invoke方法可以调用被代理类对象
2.method.invoke(ProgrammerImpl.class.newInstance(),args); 传参必须为被代理类对象,方法参数
3.method.invoke返回的是被代理类对象,可通过以下操作打印验证
System.out.println(method.invoke(ProgrammerImpl.class.newInstance(),args));
注意
1、通过以上步骤只能看出Proxy.newProxyInstance方法可以给我们获取到被代理对象,但是看不出动态性
2、可以通过多次System.out.println(coder.hashCode());来输出每次调用coder.hashCode()返回的哈希码值都不一样可以表明,每执行一次coder对象方法,系统会动态Proxy.newProxyInstance返回一个实例化对象,从而也就说明了其动态性
总结
对于动态代理的好处就是在于比较灵活,可以在我获取到目标对象之前就可以在invoke方法中去执行我想运行的方法,而不需要预先定义它