之所以写这个文章是因为我之前学代理的时候一头雾水,然后最近在学习Spring5框架的时候AOP的底层原理就是用到了动态代理,我就想着倒回去复习一下动态代理。我的学习方法是学不懂就先跳过,过了一段时间用到了再倒回来复习,我个人每次倒回来复习之前不懂的知识点,都会有一种开挂的感觉。我相信有些小伙伴也是和我一样。
话不多说,进入今天的主题。
静态代理的特点:代理类和被代理类在编译期间,就确定下来了。
静态代理需要三个要素。
① 接口
②实现接口的类 【俗称 被代理类】
③创建一个类实现接口 【俗称 代理类】
一、接口是规范,比如写dao层的时候,一般都会创建 一个接口UserDao 然后 再创建一个类 UserDaoImpl 去实现 UserDao接口
二、实现接口的类,这个就是很正常的 实现接口 然后重写抽象方法 这个没什么好说的。
三、创建一个类实现接口 为什么要创建呢?别管为什么! 反正就是要这样写
创建一个接口 ClothFactory翻译过来也就是 衣服工厂
【接口中有一个抽象方法没什么好说的!!!】
interface ClothFactory{
void produceCloth();
}
创建被代理类 NikeClothFactory翻译过来也就是耐克衣服工厂
【接口实现类,重写接口中的抽象方法也属于正常操作!!!】
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("Nike工厂生产一批运动服");
}
}
创建代理类
【创建代理类,这里需要说一下】
1、创建的代理类需要实现,和被代理类相同的接口,也就是上方的接口。
2、也需要重写抽象方法
3、有一个 被代理类类型 的 成员变量 【用来调用方法,通过代理的构造方法进行赋值】
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;//用被代理类对象进行实例化
public ProxyClothFactory(ClothFactory factory){
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做一些准备工作");
factory.produceCloth();
System.out.println("代理工厂做一些后续的收尾工作");
}
}
接下来是测试类:
【先创建被代理类的对象,然后通过构造方法创建代理类对象,这时候,被代理类对象已经被赋值了,然后被代理类调用方法,方法里面 调用了被代理对象的方法】
public class StaticProxyTest {
public static void main(String[] args) {
//创建被代理类的对象
ClothFactory nike = new NikeClothFactory();
//创建代理类的对象
ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
动态代理,也就是不在编译时创建代理类,而是在运行时,自动创建代理类。从而实现动态代理的动态性。动态代理需要以下三个要素
①接口
②接口实现类
③代理类工厂 (用来创建代理类的工厂)
这两个都是正常的操作,没什么好说的。
接口 Human翻译过来也就是 人
interface Human{
String getBelief();
void eat(String food);
}
被代理类 SuperMan翻译过来也就是 超人
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
代理类工厂
工厂类中有一个创建代理类对象的方法,参数是被代理类对象,返回的是被代理类对象。MyInvocationHandler是自定义的一个类,因为newProxyInstance()方法中的第三个参数需要一个实现InvocationHandler接口的类,bind()也是自定义的方法。
class ProxyFactory{
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj){//obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
}
MyInvocationHandler类
创建代理类对象的时候会自动调用本类中的 invoke()方法,bind()方法是为了给 被代理类类型 的 成员变量赋值,invoke()方法的
第一个参数是 代理类对象,
第二个参数是 代理类对象调用的方法,method.invoke()方法是反射的invoke()方法,
第三个参数是 方法的参数
class MyInvocationHandler implements InvocationHandler{
private Object obj;//需要使用被代理类的对象进行赋值
public void bind(Object obj){
this.obj = obj;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
//将被代理类要执行的方法a的功能就声明在invoke()中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
//obj:被代理类的对象
Object returnValue = method.invoke(obj,args);
//上述方法的返回值就作为当前类中的invoke()的返回值。
return returnValue;
}
}
测试类代码:
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//proxyInstance:代理类的对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
//当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("四川麻辣烫");
System.out.println("*****************************");
NikeClothFactory nikeClothFactory = new NikeClothFactory();
ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
proxyClothFactory.produceCloth();
}
}
到这里,本篇文章就讲解结束,如果有看不懂的,可以去尚硅谷找java课程,代码来自尚硅谷宋红康,我个人也是康师傅的忠实粉丝。