昨天是第一次投简历后,第一次接到了电话面试,然后发现对几个知识点还是挺模糊的,所以打算写几篇博客来加深一下理解
先来一段百度的解释:
就是为一个对象提供一个代理以控制对这个对象的访问,很容易理解,举个例子,我们想要邀请小明表演节目,必须先要通过他的经纪人,再让他的经纪人去和他沟通,在这个流程里面,小明就是被代理对象,经纪人就是他的代理对象,这样的好处是什么呢,好处就在于小明只需要在指定时间,指定地点参加表演,而其他的比如什么时候,什么地点,这些都交给经纪人去处理,所以在代码层面来说,就是可以在被代理对象的基础上,实现功能的扩展和业务的控制
代理模式根据代理类创建的时期,分为静态代理,动态代理
静态代理,是指程序运行之前,代理类就已经被程序员写好,这种是最简单的代理模式,举个例子,当我写了一个接口IA,然后我再写一个被代理类A,再写一个PA,然后写main方法,然后运行,这种在运行之前,代理类就已经写好的,就是静态代理,上代码
/**
*
* @author Dong
*
*/
public interface ApplicationSoftware {
public void mehtod();
}
/**
*
* @author Dong
*
*/
public class Software implements ApplicationSoftware {
private String name;
public Software(String name) {
this.name = name;
}
@Override
public void mehtod() {
System.out.println("我是" + name);
}
}
/**
*
* @author Dong
*
*/
public class SoftwareProxy implements ApplicationSoftware {
private ApplicationSoftware applicationSoftware;
private String name;
public SoftwareProxy(String name) {
this.name = name;
}
@Override
public void mehtod() {
if(applicationSoftware == null){
applicationSoftware = new Software(name);
}
System.out.println("我是代理");
applicationSoftware.mehtod();
}
}
/**
*
* @author Dong
*
*/
public class Test {
public static void main(String[] args) {
ApplicationSoftware applicationSoftware = new SoftwareProxy("idea");
applicationSoftware.mehtod();
}
}
从代码中可以看出,静态代理可以做到,在符合开闭原则的前提下,实现对代理类的功能扩展,但是缺点是,如果存在多个被代理类,就需要对应的写多个代理类,工作量很大,而且接口一旦更改,那么所有的子类都需要做对应的更改,十分不方便
所以为了解决这些问题,就出现了动态代理
动态代理,是指我们不需要再手动的去写代理类,而是让jvm,在程序运行的时候,动态的创建代理对象(注意:不再是创建代理类了,而是直接创建代理对象),他和静态代理相比,就是代理对象可以不实现接口,可能不是很容易理解,等会用代码来解释,在上代码之前,需要知道,实现动态代理的两种方式,利用JDK中自带生成代理类的API,利用Cglib代理
JDK实现代理,首先需要我们自己创建动态处理器,然后使用newProxyInstance方法获取代理对象,该方法有三个参数,第一个参数是指定被代理对象所使用的类加载器,获取加载器的方法是固定的,第二个参数是指定被代理对象实现的接口的类型,使用泛型方式确认类型,是一个数组,因为一个类可以实现多个接口嘛,第三个参数是我们自己创建的动态处理器,在执行被代理对象的方法时,会触发动态处理器里面的方法
因为这种方式实现动态代理,是使用了java的反射机制,所以有两个要求,一就是被代理对象必须要实现接口,二就是代理对象必须要指定接口类型,否则无法实现动态代理,下面上代码
首先,还是上面的例子,接口和被代理类不变,我们创建一个动态处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
*
* @author Dong
*
*/
public class ProxyHandler implements InvocationHandler {
// 被代理对象
private Object object;
public ProxyHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理开始");
Object result = method.invoke(object, args);
System.out.println("动态代理结束");
return result;
}
}
接下来不再使用我们之前创建的静态代理类,修改main方法
import java.lang.reflect.Proxy;
/**
*
* @author Dong
*
*/
public class Test {
public static void main(String[] args) {
ApplicationSoftware as = (ApplicationSoftware) Proxy.newProxyInstance(Test.class.getClassLoader(),
new Class[]{ApplicationSoftware.class},
new ProxyHandler(new Software("idea")));
as.mehtod();
}
}
这就是利用JDK中自带生成代理类的API的动态代理了,主要通过java的反射机制,拦截被代理类的方法,然后对拦截的方法进行控制,从而生成代理对象,可以看到,在动态处理器里面,被代理类使用的Object类,这样的话可以使得程序更灵活,可以处理各种被代理类
和静态代理相比,这种方式是不再需要创建多个代理类了,同时也降低了程序的耦合,已经基本上解决了我们的问题,但是美中不足的是,被代理类还是需要实现接口才能使用这个方式,那么还有没有更强大的方式呢,Cglib可以做到
对于没有实现接口的单一对象,我们要对其实现代理,可以从其子类入手,Cglib就是通过底层字节码,为被代理类创建一个子类,从而实现对被代理类的功能扩展,但是因为使用的继承,所以对final修饰的类,和private修饰的方法,不能进行代理
使用Cglib之前,需要先导包,需要导入
这个在maven上去下载吧,我就不提供了,毕竟用的不多
maven仓库网址:mvnrepository.com
下面上代码
首先修改被代理类
/**
*
* @author Dong
*
*/
public class Software{
private String name;
public Software(String name) {
this.name = name;
}
public Software(){
}
public void mehtod() {
System.out.println("我是" + name);
}
}
然后编写Cglib代理类
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
*
* @author Dong
*
*/
public class CglibProxy implements MethodInterceptor {
// 被代理类
private Object object;
/**
* 获取代理对象
* @return
*/
public Object getProxyInstance(Object object){
this.object = object;
Enhancer en = new Enhancer();
en.setSuperclass(object.getClass());
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object object, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("动态代理开始");
Object result = method.invoke(this.object, args);
System.out.println("动态代理结束");
return result;
}
}
修改main方法
/**
*
* @author Dong
*
*/
public class Test {
public static void main(String[] args) {
Software software = (Software) new CglibProxy().getProxyInstance(new Software("idea"));
software.mehtod();
}
}
需要注意的地方是,在被代理类里面,我加上了一个无参的构造方法,原因是在return en.create(); 这个地方我没有传递参数,这句话的意思是创建被代理类的子类对象,然后返回,如果父类的构造方法需要参数,那么就需要传递参数,否则会出错,所以为了方便就直接提供一个无参的构造方法
然后对于被代理的拦截处理都是一样的操作,所以就没有再截结果的图了
可以看出,Cglib弥补了使用JDK自带的API的不足的地方,对于没有实现接口的类也可以进行动态代理,而且性能也更高,但是Cglib创建代理对象也要比JDK的更费事,二者各有所长,在Spring-AOP中就是使用了这两种方式结合
再来说一下和别的类似的设计模式的区别,代理模式属于结构型模式,那么在结构型模式里面,适配器模式和装饰者模式是和代理模式最相似的,都是通过一个中间类,来间接访问目标类,但是区别在于
所以对于全部的23种设计模式,有很多的实现方式是很相似的,除了创建型,结构型,行为型三个大类很容易区分,大部分是很相似的,只有根据设计模式的原本作用去区分
https://www.cnblogs.com/cenyu/p/6289209.html
https://www.cnblogs.com/daniels/p/8242592.html