代理模式:
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
代理分类:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
一、静态代理
1.业务接口
public interface Account {
void deposit(); //存款
void draw(); //取款
}
2.业务接口实现
public class AccountImpl implements Account {
@Override
public void deposit() {
System.out.println("取款");
}
@Override
public void draw() {
System.out.println("存款");
}
}
3.代理类
public class AccountProxy implements Account {
private Account account;
public AccountProxy(Account account) {
this.account = account;
}
@Override
public void deposit() {
System.out.println("取款前校验");
account.deposit();
System.out.println("取款后通知");
}
@Override
public void draw() {
System.out.println("存款前校验");
account.draw();
System.out.println("存款后通知");
}
}
4.测试调用
public class MainTest {
public static void main(String[] args) {
Account account = new AccountImpl();
Account accountProxy = new AccountProxy(account);
accountProxy.deposit();
accountProxy.draw();
}
}
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
二、动态代理
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
(1).JDK动态代理
JDK动态代理中包含一个类和一个接口:
1.InvocationHandler接口:
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
参数:
proxy - 被代理的对象。
method -要调用的方法。
args - 方法调用时所需的参数。
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
2.Proxy类:
package java.lang.reflect;
public class Proxy implements java.io.Serializable {
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
{...}
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{...}
public static boolean isProxyClass(Class<?> cl) {...}
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException
{...}
}
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
例子:
1.业务接口
public interface Account {
void deposit(); //存款
void draw(); //取款
}
2.业务接口实现
public class AccountImpl implements Account {
@Override
public void deposit() {
System.out.println("取款");
}
@Override
public void draw() {
System.out.println("存款");
}
}
3.代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class AccoutJDKDynProxy implements InvocationHandler {
private Object targetObj;
public Object getProxy(Object targetObj) {
this.targetObj = targetObj;
return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("操作前验证");
method.invoke(targetObj, args);
System.out.println("操作后通知");
return result;
}
}
4.测试调用
public class MainTest {
public static void main(String[] args) {
Account account = new AccountImpl();
AccoutJDKDynProxy proxy = new AccoutJDKDynProxy();
Account accountProxy = (Account) proxy.getProxy(account);
accountProxy.deposit();
accountProxy.draw();
}
}
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
(2).Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
1.业务接口
public interface Account {
void deposit(); //存款
void draw(); //取款
}
2.业务接口实现
public class AccountImpl implements Account {
@Override
public void deposit() {
System.out.println("取款");
}
@Override
public void draw() {
System.out.println("存款");
}
}
3.代理类
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 AccountCglibDynProxy implements MethodInterceptor {
private Object targetObj;
public Object getProxy(Object target) {
this.targetObj = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.targetObj.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
System.out.println("操作前验证");
Object result = proxy.invokeSuper(obj, args);
System.out.println("操作后通知");
return result;
}
}
4.测试调用
public class MainTest {
public static void main(String[] args) {
Account account = new AccountImpl();
AccountCglibDynProxy proxy = new AccountCglibDynProxy();
Account accountProxy = (Account) proxy.getProxy(account);
accountProxy.deposit();
accountProxy.draw();
}
}