还有一个有趣的作用是可以用作远程调用,比如现在有Java接口,这个接口的实现部署在其它服务器上,在编写客户端代码的时候,没办法直接调用接口方法,因为接口是不能直接生成对象的,这个时候就可以考虑代理模式(动态代理)了,通过Proxy.newProxyInstance代理一个该接口对应的InvocationHandler对象,然后在InvocationHandler的invoke方法内封装通讯细节就可以了。具体的应用,最经典的当然是Java标准库的RMI,其它比如hessian,各种webservice框架中的远程调用,大致都是这么实现的。
动态代理我们分之为jdk动态代理和cglib动态代理
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
1.JDK动态代理
·此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。
JDK动态代理只能针对实现了接口的类生成代理。
看看代码:
dao实现类
public class UserDaoImpl implements UserDao {
public void add() {
System.out.println("add success");
}
}
public class ProxySubject implements Subject {
private Subject realSubject;
public String request() {
System.out.println("代理增强");
return realSubject.request();
}
public Subject getRealSubject() {
return realSubject;
}
public void setRealSubject(Subject realSubject) {
this.realSubject = realSubject;
}
public class RealSubject implements Subject {
public String request() {
// TODO Auto-generated method stub
return "真实主题";
}
}
*/
public interface Subject {
public String request();
}
test
public static void main(String[] args) {
/**
* 静态代理
*/
/*Subject sub=new RealSubject();//被代理对象
System.out.println(sub.toString());
ProxySubject ps=new ProxySubject();//代理对象
System.out.println(ps.toString());
ps.setRealSubject(sub);
String request = ps.request();//走真实代理对象 RealSubject
System.out.println(request);*/
/**
* 动态代理
*/
final UserDao dao=new UserDaoImpl();
//代理对象
//第一个参数:获取和dao一样的类加载器,通过反射机制获取类加载器
//new InvocationHandler()叫匿名内部类,拿到了接口的实现类
UserDao newProxyInstance = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler() {
//newProxyInstance 被代理对象
public Object invoke(Object newProxyInstance, Method method, Object[] args)
throws Throwable {
System.out.println("增强");
//原始对象 dao 真正的dao
Object invoke = method.invoke(dao, args);
System.out.println("记录日志");
return invoke;
}
});
//增强代理对象,方法
newProxyInstance.add();
}
applicationContext.xml