定义
百度百科:代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
个人理解:在编程过程中想对某一些功能进行升级或者附加别的功能,但是又不想修改原本代码的时候,直接在外面在套一层,在调用的时候去调用这外面这一层的对象对应的方法来实现功能的升级或者附加。
使用场景
调试、远程方法调用、功能扩展
类的视图
静态代理
动态代理
代码示例
静态代理
静态代理主要就是被代理对象和代理对象都实现同一个接口,在代理对象中包含一个被代理对象的类型的字段,并且在实例化代理对象的时候需要将被代理对象初始化赋值,一般都是直接定义一个入参为被代理对象的构造函数。然后在代理对象中进行处理。
下面我们定义一个代理接口
我们模拟一个小孩测体温的过程
//这个接口是一组被代理对象的抽象接口
//定义一个代理接口
interface Movable{
void move();
}
然后是我们的被代理对象
//被代理对象需要继承代理接口
class Child implements Movable{
@Override
public void move() {
//这里是业务
System.out.println("小孩在测体温");
}
}
在然后是代理对象
//代理对象
class Parents implements Movable{
//被代理对象或者被代理对象的父类
Movable m;
//包含被代理对象的构造函数
public Parents(Movable m) {
this.m = m;
}
//扩展功能
public void start(){
System.out.println("父母记录开始时间");
}
//扩展功能
public void end(){
System.out.println("父母记录结束时间");
}
@Override
public void move() {
start();
//注意:这里要调用被代理者的方法
m.move();
end();
}
}
执行结果
动态代理
动态代理相对于静态代理来说更加的灵活,同一个代理对象可以处理不同的被代理对象(没有共同的实现接口以及方法)。
动态代理分为jdk和cglib(使用的时候需要导入依赖),两者写法有一点点差异,相对而言cglib的更加简单些,少了一个代理接口,但是都是使用了asm来进行反射操作,只是实现过程有所不同。
jdk的动态代理机制是代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。
cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
下面是代码示例
jdk动态代理
这里和前面都是没有区别的
//定义一个代理接口
interface Movable{
void move();
}
//被代理对象需要继承代理接口
class Child implements Movable {
@Override
public void move() {
System.out.println("小孩在测体温");
}
}
重点在于代理对象的不同
这里需要继承InvocationHandler
class Parents<T> implements InvocationHandler{
//被代理的对象
T target;
public Parents(T target) {
this.target = target;
}
public void start(){
System.out.println("父母记录开始时间");
}
public void end(){
System.out.println("父母记录结束时间");
}
/**
* @param proxy 生成的代理对象,这里就是movable
* @param method 要执行的方法,这里就是move()
* @param args 执行方法的入参
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
start();
/**
* 调用被代理对象的 move()方法
* public Object invoke(Object obj, Object... args)
* obj 被代理对象
* args 执行方法的入参
*/
Object result = method.invoke(target,args);
end();
return result;
}
}
最后是main方法中执行
public static void main(String[] args) {
Child child = new Child();
/**
* public static Object newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
*
* ClassLoader loader,生成的代理对象的类型,一般用被代理对象的类型
* Class<?>[] interfaces,生成的代理对象要继承的接口,可以是多个
* InvocationHandler h ,被代理对象的被代理方法被调用的时候的处理方法
*/
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles" , "true");
Movable movable = (Movable) Proxy.newProxyInstance(Child.class.getClassLoader(),
new Class[]{Movable.class},
new Parents<Movable>(child));
movable.move();
}
cglib动态代理
这里要注意区别,CGLIB实现动态代理不需要被代理的类型实现接口并且代理类的处理方法实现的接口不同,剩下的这里就不在絮叨了,直接上代码,懂了jdk的cglib的就不难了。
/**
* CGLIB实现动态代理不需要接口
*/
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Child.class);
enhancer.setCallback(new Parents());
Child child = (Child)enhancer.create();
child.move();
}
}
class Parents implements MethodInterceptor {
public void start(){
System.out.println("父母记录开始时间");
}
public void end(){
System.out.println("父母记录结束时间");
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(o.getClass().getSuperclass().getName());
start();
Object result = null;
result = methodProxy.invokeSuper(o, objects);
end();
return result;
}
}
class Child {
public void move() {
System.out.println("小孩在测体温");
}
}
注意
- JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。
- cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
- 在jdk6之后的版本jdk的动态代理比cglib的要快,1W次执行下,差不多是百分之20的差距。
结尾
感谢大家的耐心阅读,如有建议请私信或评论留言。
如有收获,劳烦支持,关注、点赞、评论、收藏均可,博主会经常更新,与大家共同进步
如有不足之处请批评指正。