代理模式
代理模式最主要的就是有一个公共的接口,一个具体的类,一个代理类。代理类持有具体类的实例,代理类执行具体类实例方法。代理类主要负责为委托类预处理消息,过滤消息,把消息转发给委托类,以及事后处理消息等。
代理模式结构图(《大话设计模式》)
静态代理
下面是静态代理的实现
- 创建一个公共的接口
public interface Person {
void giveMoney();
}
- Student类实现Person接口。Student可以具体实施动作。
public class Studen implements Person {
private String name;
public Studen(String name) {
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + " Student执行");
}
}
- StudentProxy类也实现了Person接口,它代理Student执行动作
public class StudentsProxy implements Person {
Studen stu;
public StudentsProxy(Person stu) {
if (stu.getClass() == Studen.class) {
this.stu = (Studen) stu;
}
}
@Override
public void giveMoney() {
stu.giveMoney();
}
}
- 测试
public class StudentsProxyTest {
public static void main(String[] args){
Person person = new Studen("proxy");
Person monitor = new StudentsProxy(person);
monitor.giveMoney(); // proxy Student执行
}
}
这里没有直接通过Studen的实例直接执行动作,而是通过代理执行了。
代理模式就是在实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。可以在代理过程中加上一些其他用途。
public class StudentsProxy implements Person {
Studen stu;
public StudentsProxy(Person stu) {
if (stu.getClass() == Studen.class) {
this.stu = (Studen) stu;
}
}
@Override
public void giveMoney() {
System.out.println("before --StudentProxy");
stu.giveMoney();
System.out.println("after --StudentProxy");
}
}
结果:
before --StudentProxy
proxy Student执行
after --StudentProxy
动态代理
JDBC 动态代理
在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。
- 创建需要代理的实现类:
public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void giveMoney() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+" Student执行");
}
}
- 创建一个检测方法执行时间的工具类:
public class MonitorUtil {
private static ThreadLocal<Long> t1 = new ThreadLocal<>();
public static void start() {
t1.set(System.currentTimeMillis());
}
public static void finish(String mothodName){
long finishTime= System.currentTimeMillis();
System.out.println(mothodName+" 耗时 "+(finishTime-t1.get())+"ms");
}
}
- 创建StuInvocationHandler类,实现InvocationHandler接口。
public class StuInvocationHandler implements InvocationHandler {
/**
* 真实的服务对象
*/
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法");
MonitorUtil.start();
Object result = method.invoke(target, args);
MonitorUtil.finish(method.getName());
return result;
}
}
- 测试
public static void main(String[] args) {
StuInvocationHandler invocationHandler = new StuInvocationHandler();
Person porxy = (Person) invocationHandler.bind(new Student("proxy"));
porxy.giveMoney();
}
}
结果:
代理执行giveMoney方法
proxy Student执行
giveMoney 耗时 10000ms
JDK动态代理的代理对象在创建时,需要使用业务实现类所时间的接口作为参数(后面代理方法时需要根据接口的方法名进行调用)。如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。并且,如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(无法被调用)
CGLIb动态代理
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
-
引入cglib的包
-
创建需要代理的实现类
//这里可以不用实现接口
public class Student {
private String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public void giveMoney() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+" Student执行");
}
}
- 创建StuMethodInterceptor,实现 MethodInterceptor接口
public class StuMethodInterceptor implements MethodInterceptor {
/**
* 创建代理对象
* @param c 代理对象
* @param args 对应的构造器参数类型
* @param argsValue 对应的构造器参数值
* @param <T> <泛型方法>
* @return 返回的代理对象类型
*/
public <T> T getProxy(Class c,Class[] args,Object[] argsValue){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(c);
enhancer.setCallback(this);
return (T) enhancer.create(args,argsValue);
}
/**
* 创建代理对象
* @param c 代理对象Class 必须有一个无参数构造器
* @param <T> <泛型方法>
* @return 返回代理对象
*/
public <T> T getProxy(Class c) {
//增强器,动态代码生成器
Enhancer enhancer = new Enhancer();
//设置创建子类的类
enhancer.setSuperclass(c);
enhancer.setCallback(this);
return (T) enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法");
MonitorUtil.start();
Object result = proxy.invokeSuper(obj, args);
MonitorUtil.finish(method.getName());
return result;
}
}
- 测试
public class StuMethodInterceptorTest {
public static void main(String[] args) {
StuMethodInterceptor interceptor = new StuMethodInterceptor();
// Student student = interceptor.getProxy(Student.class);
Student student = interceptor.getProxy(Student.class,
new Class[]{String.class},new Object[]{"proxy"});
student.giveMoney();
// 代理执行giveMoney方法
// proxy Student执行
// giveMoney 耗时 10015ms
}
}