代理模式
代理模式是一种很常见的设计模式,代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
3种实现方式
- 静态代理
- 动态代理
- jdk代理
- cglib代理
静态代理
public interface Server {
void send();
}
public class ServerTarget implements Server {
@Override
public void send() {
System.out.println("send!");
}
}
public class StaticProxy implements Server {
private Server server;
public StaticProxy(Server server){
this.server = server;
}
@Override
public void send() {
System.out.println("before!");
server.send();
System.out.println("afer!");
}
}
public class TestMain {
public static void main(String[] args) {
Server s = new StaticProxy(new ServerProxy());
s.send();
}
}
优点:在不修改目标类的情况下,可以对目标类进行扩展。
缺点:代理类和目标类需要实现一样的接口,假如代理类很多,维护起来就很麻烦。
动态代理---jdk代理
基于静态代理类代码的基础上,再多写一些类,后面基于静态代理类再说下区别。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before");
Object result = method.invoke(this.obj, args);
System.out.println("after");
return result;
}
}
public interface Client {
void receive();
}
public class ClientTarget implements Client {
@Override
public void receive() {
System.out.println("receive!");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestMain {
public static void main(String[] args) {
Server ser = new ServerTarget();
InvocationHandler handler = new DynamicProxy(ser);
Server s = (Server)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
ser.getClass().getInterfaces(),
handler);
s.send();
Client cli = new ClientTarget();
InvocationHandler handlers = new DynamicProxy(cli);
Client c = (Client)Proxy.newProxyInstance(handlers.getClass().getClassLoader(),
cli.getClass().getInterfaces(),
handlers);
c.receive();
}
}
假如上面的代码是基于静态代理类的模式来实现,其维护成本就很高了,代理类ServerProxy对目标类ServerTarget的方法进行了扩展,且代理类StaticProxy和目标类ServerTarget都实现了Server接口,现在新的目标类ClientTarget也有相同的需求,那就必须也实现Server接口了,动态代理就是将相同的业务需求抽象出来,不需要实现代理类的接口,只需要实现InvocationHandler接口,维护性相对于静态代理来说,已经好很多了。
动态代理---cglib代理
静态代理和jdk动态代理,目标对象都需要实现接口,有没有不需要实现接口的方法呢,答案就是cglib代理。cglib代理是以目标对象子类的方式类实现代理的。需要下载cglib的jar包,这里导入的cglib-nodep-2.1_3.jar。
public class ServersTarget {
public void send() {
System.out.println("send!");
}
}
```java
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor{
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("before");
Object returnValue = method.invoke(target, args);
System.out.println("after");
return returnValue;
}
}
public class TestMain {
public static void main(String[] args) {
ServersTarget st = new ServersTarget();
ServersTarget stProxy = (ServersTarget)new CglibProxy(st).getProxyInstance();
stProxy.send();
}
}
由于CGLib是采用动态创建子类的方法,对于final标识的类无法被继承,会抛出异常。
对于final标识的方法,intercept不生效,直接调用父类方法,不能代理。
CGLib动态代理对象性能比JDK动态代理对象的性能高不少,但CGLib在创建代理对象时所花费的时间却比JDK多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。