文章目录
前言
这是一个新的系列,主要用来记录复盘java基础时候的一些笔记。
一、静态代理
在正式介绍静态代理之前呢,先看下代理模式的定义:代理模式为其他对象提供一种代理以控制对这个对象的访问。
那什么又是静态代理呢,简单来讲,就是要创建出一个代理类,这个代理类与目标类实现了同一个接口,当去使用目标对象的时候,不是直接创建目标对象,而是创建代理对象,去调用目标对象中的方法。
接下来看下每个部分的代码:
代理了和目标类继承的接口:
public interface Service {
public void sing();
public void dance();
}
目标类:
public class Provider implements Service{
public void sing() {
System.out.println("正在唱歌。。。。。。");
}
public void dance() {
System.out.println("正在跳舞。。。。。。");
}
}
代理类:
public class Agent implements Service{
private Service service;
public Agent(Service service){ //代理类主要是要在构造中传入一个接口类型的参数
this.service=service;
}
public void sing() { //代理类中的方法其实,是调用传入参数的方法
service.sing();
}
public void dance() {
service.dance();
}
}
使用者:
public class Customer {
public static void main(String[] args) {
Agent agent = new Agent(new Provider()); //实例化一个代理对象,但是传入的是目标对象
agent.sing(); //这里最终调用的还是目标对象中的方法
agent.dance();
}
}
二、动态代理
静态代理其实很好理解,就是要创建一个代理对象,去代理目标对象。那么动态代理又是什么呢?
基于静态代理的理解上,动态代理其实就是直接给某一个目标对象生成一个代理对象,而不需要代理类存在,动态代理与静态代理原理是一样的,只是它没有具体的代理类,而直接通过反射生成了一个代理对象。
这里,是借助Proxy下的newProxyInstance()来实现直接生成代理对象的。需要注意的是Proxy是reflect包下的。
接口和目标类的方法其实和静态代理是一样的,这里就不写了。直接看下在使用的时候,如何动态生成代理对象:
public class Customer {
public static void main(String[] args) {
//这里把目标对象的类型提升为接口类型,是为了如果有多个目标类的时候,想更换目标对象,只需要在这里更改,而不需要在下面动态代理传入的参数里面再改成新的目标对象
final Service service = new Provider();
Service agent = (Service)Proxy.newProxyInstance(service.getClass().getClassLoader(), service.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("准备中......");
method.invoke(service, null);
System.out.println("结束啦~~~");
return null;
}
});
agent.dance();
agent.Sing();
}
}
这里解释下newProxyInstance():
service.getClass().getClassLoader():这里传入的是目标类的类加载器。
service.getClass().getInterfaces():这里传入的是目标类继承的接口。
InvocationHandler():策略设计模式的应用,通过实现这个接口,说明如何代理真实对象,怎么实现代理。
invoke():(这里是InvocationHandler里面重写的方法)调用代理类的任何方法,这个方法都会执行;比如下面的agent.dance(),调用这个方法,实际上,执行的是invoke方法。
Object proxy:(invoke方法中的参数)代理对象本身的引用,这个一般不用。
Method method:(invoke方法中的参数)当前调用的方法;比如agent.dance(),那这里就会执行dance这个方法。
Object[] args:(invoke方法中的参数)当前方法用到的参数,如果没有,method.invoke()里面参数部分就传入null。
三、动态代理的应用
其实,在上面动态代理的代码中已经写到了应用的示例。
System.out.println("准备中......");
method.invoke(service, null);
System.out.println("结束啦~~~");
在每次目标对象的方法执行前和执行后,都可以执行一些其他代码,来扩展目标对象的功能。
而这么做的好处是,当这些扩展的功能都一样时,不需要在每个方法里都写一遍了,直接加在代理对象里,这样代理对象去执行这个方法的时候,扩展的功能也会执行一次。
总结
以上就是静态代理和动态代理的内容啦。