1 代理模式概要
- 分类:静态代理、动态代理
- 角色:抽象接口、代理对象、被代理对象(目标),由被代理对象来做最终的决定
- 代理对象通常来说会持有被代理对象的引用(以便代理角色完成工作之前,或者之后能找到被代理对象,能够通知被代理对象)
2 代理的实现
2.1 静态代理
定义一个抽象接口 Person
,定义一个实现类 Son
,创建一个对象 Mother
实现接口 Person
,同时持有 Person
的引用,完整代码如下
-
Person
接口
package com.lushwe.pattern.proxy;
/**
* 说明:人
*
* @author Jack Liu
* @date 2019-05-27 10:38
* @since 1.0
*/
public interface Person {
/**
* 找对象
*/
void findLove();
/**
* 找工作
*/
void findJob();
}
-
Son
类
package com.lushwe.pattern.proxy;
/**
* 说明:儿子
*
* @author Jack Liu
* @date 2019-05-27 10:38
* @since 1.0
*/
public class Son implements Person {
public void findLove() {
System.out.println("儿子找对象,肤白貌美大长腿");
}
public void findJob() {
System.out.println("儿子找工作,钱多事少离家近");
}
}
-
Mother
类
package com.lushwe.pattern.proxy.staticed;
import com.lushwe.pattern.proxy.Person;
/**
* 说明:母亲(静态代理)
*
* @author Jack Liu
* @date 2019-05-27 10:40
* @since 1.0
*/
public class Mother implements Person {
private Person person;
public Mother(Person person) {
this.person = person;
}
public void findLove() {
System.out.println("妈妈帮忙物色对象");
this.person.findLove();
System.out.println("对象是否合适");
}
public void findJob() {
// do nothing
}
}
测试代码
package com.lushwe.pattern.proxy.staticed;
import com.lushwe.pattern.proxy.Son;
/**
* 说明:静态代理测试
*
* @author Jack Liu
* @date 2019-05-27 10:43
* @since 1.0
*/
public class StaProxyTest {
public static void main(String[] args) {
Mother mother = new Mother(new Son());
mother.findLove();
}
}
运行 StaProxyTest
,日志打印结果如下
妈妈帮忙物色对象
儿子找对象,肤白貌美大长腿
对象是否合适
总结
- 优点:开发简单
- 缺点:实现类
Son
方法发生变化,代理类Mother
也要调整,不符合开闭原则
2.2 动态代理
2.2.1 JDK代理
创建 JdkMatchmaker
类,实现 InvocationHandler
接口,通过 Proxy
工具类创建代理对象,完整代码如下
package com.lushwe.pattern.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 说明:媒婆(Jdk代理)
*
* @author Jack Liu
* @date 2019-05-27 11:15
* @since 1.0
*/
public class JdkMatchmaker<T> implements InvocationHandler {
/**
* 被代理对象
*/
private T target;
/**
* 返回代理对象实例
*
* @param target
* @return
*/
public T getInstance(T target) {
this.target = target;
Class<?> targetClass = target.getClass();
return (T) Proxy.newProxyInstance(targetClass.getClassLoader(), targetClass.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("媒婆帮忙物色对象");
// 调用被代理对象方法
method.invoke(this.target, args);
System.out.println("对象是否合适");
return null;
}
}
测试代码
package com.lushwe.pattern.proxy.jdk;
import com.lushwe.pattern.proxy.Person;
import com.lushwe.pattern.proxy.Son;
/**
* 说明:Jdk动态代理测试类
*
* @author Jack Liu
* @date 2019-05-27 11:19
* @since 1.0
*/
public class JdkProxyTest {
public static void main(String[] args) {
JdkMatchmaker<Person> jdkMatchmaker = new JdkMatchmaker();
Person person = jdkMatchmaker.getInstance(new Son());
person.findLove();
}
}
运行 JdkProxyTest
,日志打印结果如下
媒婆帮忙物色对象
儿子找对象,肤白貌美大长腿
对象是否合适
总结
- 优点:动态生成代理类,被代理类接口变更,
JdkMatchmaker
不需要修改 - 缺点:被代理类必须实现接口
2.2.2 CGlib代理
创建 CglibMatchmaker
类,实现 MethodInterceptor
接口,通过 Enhancer
工具类创建代理对象,完整代码如下
package com.lushwe.pattern.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 说明:媒婆(Cglib代理)
*
* @author Jack Liu
* @date 2019-05-30 11:12
* @since 1.0
*/
public class CglibMatchmaker<T> implements MethodInterceptor {
public T getInstance(Class<T> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return (T) enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("媒婆开始物色对象");
methodProxy.invokeSuper(o, objects);
System.out.println("如果适合,交往");
return null;
}
}
测试代码
package com.lushwe.pattern.proxy.cglib;
/**
* 说明:Tom
*
* @author Jack Liu
* @date 2019-05-30 11:12
* @since 1.0
*/
public class Tom {
public void findLove() {
System.out.println("Tom找对象,肤白貌美大长腿");
}
}
package com.lushwe.pattern.proxy.cglib;
/**
* 说明:Cglib动态代理测试类
*
* @author Jack Liu
* @date 2019-05-30 11:17
* @since 1.0
*/
public class CglibProxyTest {
public static void main(String[] args) {
CglibMatchmaker<Tom> cglibMatchmaker = new CglibMatchmaker();
Tom tom = cglibMatchmaker.getInstance(Tom.class);
tom.findLove();
}
}
运行 CglibProxyTest
,日志打印结果如下
媒婆开始物色对象
Tom找对象,肤白貌美大长腿
如果适合,交往
总结
-
优点:
- i 动态生成代理类,被代理类接口变更,
CglibMatchmaker
不需要修改 - ii 代理类不需要实现接口
- i 动态生成代理类,被代理类接口变更,
-
缺点:
- i 不能对
final
类进行继承
- i 不能对
3 代理模式的应用
-
Spring Aop
就是运用动态代理实现,当被代理类实现了接口,使用Jdk动态代理
,没有实现接口,则使用Cglib动态代理
-
MyBatis DAO
也是运用动态代理,使用MyBatis
开发DAO
过程中,并不需要写DAO
的实现类,由MyBatis
通过Jdk动态代理
自动生成DAO
的实现类
网友评论