参考文章:
https://www.jianshu.com/p/41f28d7ef6f1
https://www.jianshu.com/p/bacaafb5d02d
spring底层就有用到动态代理模式,spring这个矿机中所周知是非常重要的,因此如果不学习动态代理这块内容,想学好spring是比较吃力的,当然spring还是用了动态字节码技术。
代理模式为其他对象提供了一种代理以控制对这个对象的访问,在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间启动中介的作用。客户端都是和代理打交道的,通过代理来实现与目标对象之间的交流。
1 .抽象角色(接口):声明真实对象和代理对象的共同接口。
2 .代理角色:代理对象角色内部含有对真是对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象,同事代理对象可以在执行真实对象操作时,附加其他操作,相当于对真实对象进行封装
3 . 真实角色:代理角色多代表的真实对象,是我们最终要引用的对象。
静态代理,动态代理(JDK代理、CLIB代理);
//定义一个接口,并声明接口中的方法;
public interface ISinger {
void sing();
}
//定义一个class,并实现上述接口,重写sing()方法;
public class Singer implements ISinger{
@Override
public void sing() {
System.out.println("sing a song");
}
}
//定义一个代理类,实现抽象角色接口,添加构造方法,并重写sing()方法
public class SingerProxy implements ISinger {
private ISinger iSinger ;
public SingerProxy(ISinger iSinger){
this.iSinger = iSinger;
}
@Override
public void sing() {
System.out.println("向观众问好");
iSinger.sing();
System.out.println("谢谢大家");
}
}
public class MainClass {
public static void main(String[] args) {
//创建一个真实角色
Singer singer = new Singer();
//创建一个代理角色,构造方法中需要真实角色;
ISinger singerProxy = new SingerProxy(singer);
//代理角色执行方法(代理角色内部调用真实角色对应的方法)
singerProxy.sing();
}
}
//输出如下:
"C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA .......
向观众问好
sing a song
谢谢大家
Process finished with exit code 0
java 动态代理所使用到的类位于java.lang.reflect包下,一百年主要涉及到一下两个类;
动态代理中的抽象角色代码:
//和静态代理一样,都需要有一个接口;
public interface ISinger {
void sing();
}
//定义一个class,实现抽象代码,并重写相关的方法;
public class Singer implements ISinger{
@Override
public void sing() {
System.out.println("sing a song");
}
}
无!!!(此处代理角色在测试代码中自动生成)
public class MainClass {
public static void main(String[] args) {
//1、创建一个真实角色
Singer target = new Singer();
//2、调用Proxy.newProxyInstance方法,并构造一个InvocationHandler对象,
//3、在对象内部重写invoke方法,同时调用method.invoke(target,args);
//4、并在该方法的上下添加自己的代码逻辑
//其中:target.getClass().getClassLoader():获取类加载器,用来生成代理对象;
// target.getClass().getInterfaces()获取接口元信息;
ISinger iSinger = (ISinger) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理---向观众问好");//在真实对象的方法被调用“前”编写自己的业务逻辑
Object returnValue = method.invoke(target,args);//此处通过反射调用真实对象对应的方法;
System.out.println("动态代理---向观众问好");//在真实对象的方法被调用“后”编写自己的业务逻辑
return returnValue;
}
});
iSinger.sing();
}
}
//测试结果
"C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:C:\Program.......
动态代理---向观众问好
sing a song
动态代理---向观众问好
Process finished with exit code 0
无!!!
public class Singer {
public void sing(){
System.out.println("sing a song");
}
}
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target){
this.target = target;
}
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//此处在真实对象方法执行前编写自己的业务逻辑
System.out.println("CGLIB动态代理————向观众问好");
Object returnValue = method.invoke(target,objects);//真实对象对应方法的调用;
//此处在真实对象方法执行前编写自己的业务逻辑
System.out.println("CGLIB动态代理————谢谢大家");
return returnValue;
}
}
public class MainClass {
public static void main(String[] args) {
Singer singer = new Singer();
Singer proxySinger = (Singer) new ProxyFactory(singer).getProxyInstance();
proxySinger.sing();
}
}
//输出结果:
"C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:C:\Program 。。。。。。
CGLIB动态代理————向观众问好
sing a song
CGLIB动态代理————谢谢大家
Process finished with exit code 0
在代理模式之中:代理对象和真实对象应该实现相同的功能(此功能可以表示为都需要有相同某个public方法),在面向对象的编程中,如果我们想要保证代理对象和真实对象有相同的功能,有两种方式:
如果对JAVA反射不懂,请看这里:JAVA高级特性之——反射