动态代理模式
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。—《 Head First设计模式》
换句话说,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。打个比方,现在房产中介很火,找房子都会经过中介,但是,我们买或者租的房子并不是中介卖或租自己的房子,而是他们的客户,真正需要租或者卖的是他们的客户。
代理模式,主要有三种角色:
- 抽象角色:通过接口或抽象类声明真实角色实现的业务方法;
- 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作;
- 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
静态代理
- UML图
- 代码示例
package com.myapp.pattern.proxypattern.staticpattern;
/**
* Created by lionel on 16/11/24.
*/
public interface Subject {
void request();
}
package com.myapp.pattern.proxypattern.staticpattern;
/**
* Created by lionel on 16/11/24.
*/
public class RealSubject implements Subject {
public void request() {
System.out.println("this is static pattern...");
}
}
package com.myapp.pattern.proxypattern.staticpattern;
/**
* Created by lionel on 16/11/24.
*/
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
public void request() {
System.out.println("preparation ...");
realSubject.request();
System.out.println("end ...");
}
}
package com.myapp.pattern.proxypattern.staticpattern;
/**
* Created by lionel on 16/11/25.
*/
public class Client {
public void proxy() {
RealSubject realSubject = new RealSubject();
Subject subject=new ProxySubject(realSubject);
subject.request();
}
}
测试结果:
不足之处
这种静态的代理模式固然在访问无法访问的资源,增强现有的接口业务功能方面有很大的优点,但是大量使用这种静态代理,会使我们系统内的类的规模增大,并且不易维护;并且由于 ProxyProxySubject 和 RealSubject 的功能本质上是相同的,都实现了 Subject 的接口,ProxySubject 只是起到了中介的作用,这种代理在系统中的存在,导致系统结构比较臃肿和松散。
这就产生了动态代理:在运行状态中,需要代理的地方,根据 Subject 和RealSubject,动态地创建一个Proxy,用完之后,就会销毁,这样就可以避免了 Proxy 角色的class在系统中冗杂的问题了。
jdk动态代理
动态代理的实现可以有 java 中的反射机制来完成,反射机制的知识大家可以去网上查看相关教程,这里就不再详细介绍了。
- jdk 动态代理是怎么动态的生成一个代理类的
这就归功于 java 中的 Proxy类,它可以动态的生成一个代理类对象,调用它的newProxyInstance()方法:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
如代码所示,它含有三个参数:
loader
: 用来生成代理类的对象;interfaces
:代理类需要实现的class 对象数组;h
:实现了InvocationHandler接口的对象,InvocationHandler类在 java.lang.reflect包中。
InvocationHandler接口下只有一个invoke()方法:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
该方法同样也有三个参数:
proxy
:代理类的实例;method
:需要执行的方法;args
:方法的参数
代码示例
package com.myapp.pattern.proxypattern.dynamicpattern.jdk;
/**
* Created by lionel on 16/11/23.
*/
public interface TicketService {
/**
* 卖票
*/
void sellTicket();
/**
* 退票
*/
void withdrawTicket();
}
package com.myapp.pattern.proxypattern.dynamicpattern.jdk;
/**
* Created by lionel on 16/11/23.
*/
public class OnlineBookingService implements TicketService {
public void sellTicket() {
System.out.println("sell ticket in internet");
}
public void withdrawTicket() {
System.out.println("withdraw ticket in internet");
}
}
package com.myapp.pattern.proxypattern.dynamicpattern.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Created by lionel on 16/11/23.
*/
public class InvocationHandlerImpl implements InvocationHandler {
private OnlineBookingService onlineBooking;
public InvocationHandlerImpl() {
}
public InvocationHandlerImpl(OnlineBookingService onlineBooking) {
super();
this.onlineBooking = onlineBooking;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("you are going to invoking" + method.getName() + "...");
method.invoke(onlineBooking, args);
System.out.println(method.getName() + "invocation has been completed...");
return null;
}
}
package com.myapp.pattern.proxypattern.dynamicpattern.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* Created by lionel on 16/11/23.
*/
public class Client {
public void proxy() {
OnlineBookingService onlineBooking = new OnlineBookingService();
InvocationHandler invocationHandler = new InvocationHandlerImpl(onlineBooking);
Class cls = onlineBooking.getClass();
TicketService ticketService = (TicketService) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), invocationHandler);
ticketService.sellTicket();
System.out.println();
ticketService.withdrawTicket();
}
}
//测试类
package com.myapp.pattern.proxyPattern.jdk;
import com.myapp.pattern.proxypattern.dynamicpattern.jdk.Client;
import org.junit.Test;
/**
* Created by lionel on 16/11/23.
*/
public class ProxyPatternTest {
@Test
public void proxyPatternTest(){
Client client=new Client();
client.proxy();
}
}
测试结果:
cglib动态代理
通过以上介绍,了解了 jdk 动态代理的原理,jdk代理机制只能代理实现了接口的类,而没有实现接口的类就不能实现的 jdk 的动态代理,而cglib 就是针对类来实现代理,
它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
拦截器:实现MethodInterceptor接口的类,在intercept方法中实现对代理目标类的方法拦截。
public Object intercept(Object obj, java.lang.reflect.Method method,
Object[] args,MethodProxy proxy) throws Throwable;
如代码所示,它有四个参数:
- obj
:目标类的实例;
- method
:目标类方法的发射对象;
- args
:方法参数;
- proxy
:代理类实例;
mavan项目 引入cglib依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
代码示例
package com.myapp.pattern.proxypattern.dynamicpattern.cglib;
/**
* Created by lionel on 16/11/23.
*/
public class Programmer {
public void code() {
System.out.println("I am just a programmer");
}
}
package com.myapp.pattern.proxypattern.dynamicpattern.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Created by lionel on 16/11/23.
*/
public class Leader implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Let me see your code...");
methodProxy.invokeSuper(o, objects);
System.out.println("oh,this code is too bad...");
return null;
}
}
package com.myapp.pattern.proxypattern.dynamicpattern.cglib;
import net.sf.cglib.proxy.Enhancer;
/**
* Created by lionel on 16/11/23.
*/
public class Client {
public void proxy() {
Programmer programmer = new Programmer();
Leader leader = new Leader();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(programmer.getClass());
enhancer.setCallback(leader);
Programmer proxy = (Programmer) enhancer.create();
proxy.code();
}
}
//测试类
package com.myapp.pattern.proxyPattern.cglib;
import com.myapp.pattern.proxypattern.dynamicpattern.cglib.Client;
import org.junit.Test;
/**
* Created by lionel on 16/11/23.
*/
public class CglibProxyTest {
@Test
public void test(){
Client client=new Client();
client.proxy();
}
}
测试结果: