1. 静态代理(可以面向接口,也可以面向类):
执行入口是代理类,目标类在代理中注册执行
静态代理实例
public interface HKworkday { //接口
public void HKeat();
public void HKdo(String work);
}
public class HKworkdayImpl implements HKworkday { //实现类
@Override
public void HKeat() {
System.out.println("HKworkdayImpl.HKeat()");
}
@Override
public void HKdo(String work) {
System.out.println("HKworkdayImpl.HKdo(" + work + ")");
}
}
public class HKweekday { //父类
public void HKplay() {
System.out.println("HKweekday.HKplay()");
}
}
public class StaticProxy extends HKweekday implements HKworkday { //继承HKweekday,实现HKworkday
private HKworkday workday;
private HKweekday weekday;
public StaticProxy(HKworkday workday, HKweekday weekday) {
this.workday = workday;
this.weekday = weekday;
}
@Override
public void HKeat() { //重写方法
System.out.println(" before HKworkdayImpl.HKeat()");
workday.HKeat();
System.out.println(" after HKworkdayImpl.HKeat()");
}
@Override
public void HKdo(String work) { //重写方法
System.out.println("before HKworkdayImpl.HKdo(" + work + ")");
workday.HKdo(work);
System.out.println("after HKworkdayImpl.HKdo(" + work + ")");
}
@Override
public void HKplay() { //重写方法
System.out.println("before HKweekdayImpl.HKplay()");
weekday.HKplay();
System.out.println("after HKweekdayImpl.HKplay()");
}
}
public class StaticProxyMain {
public static void main(String[] args) {
HKworkday workday = new HKworkdayImpl();
HKweekday weekday = new HKweekday();
workday.HKeat();
workday.HKdo("software");
weekday.HKplay();
StaticProxy proxy = new StaticProxy(workday, weekday);
proxy.HKeat();
proxy.HKdo("software");
proxy.HKplay();
}
}
其实,静态代理的关键是将目标对象,作为代理类的属性,在代理类中注册,在代理类的方法中调用目标对象方法,并在目标对象方法前后织入代码,但是需要使用代理类功能的目标类方法,都要在代理类中实现,如此一来,原来的直接体现业务逻辑流程的代码,要用代理改写,而改写后,通过阅读代码很难理解业务逻辑流程;至于代理类是否extends目标对象的类,或者implements目标对象的类,会影响代理类中的代码编写方法;因此java静态代理的实现,跟类或者接口是无关的,都能实现
2. 动态代理(面向接口)
执行入口是目标类,代理类通过java反射和代理机制在目标中注册执行,由JDK创建
动态代理实例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public interface HKworkday { //接口
public void HKeat();
public void HKdo(String work);
}
public interface HKweekday { //接口
public void HKplay();
}
public class HKlife implements HKworkday, HKweekday { //实现类
@Override
public void HKeat() {
System.out.println("HKlife.HKeat()");
}
@Override
public void HKdo(String work) {
System.out.println("HKlife.HKdo(" + work + ")");
}
@Override
public void HKplay() {
System.out.println("HKlife.HKplay()");
}
}
public class DynamicProxy implements InvocationHandler { //代理
private Object proxied;
public DynamicProxy(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----START----");
Object obj = method.invoke(proxied, args); // java的反射
System.out.println("----END----");
return obj;
}
}
public class DynamicProxyMain {
public static void main(String[] args) {
Object obj = Proxy.newProxyInstance(HKworkday.class.getClassLoader(), new Class<?>[] { HKworkday.class, HKweekday.class }, new DynamicProxy(new HKlife()));
HKworkday workday = (HKworkday) obj;
workday.HKeat();
workday.HKdo("software");
HKweekday weekday = (HKweekday) obj;
weekday.HKplay();
}
}
相较于静态代理而言,JDK动态代理是通过java的反射和代理机制,将代理类的功能反向注入到目标类中,因此,原来体现业务逻辑流程的代码在不需要过多的人工改变情况下,就可以完成目标类的功能和代理类的功能组合。通过阅读源代码,还是很容易理解业务逻辑流程,只是在执行时会在逻辑流程的前后,被自动织入代理类功能。
3. 代理的使用
A. 静态代理的实现需要花时间写大量代码,并且干扰原有的业务逻辑代码,因此大部分的开发中都不使用静态代理,静态代理的性能无问题;
B. 动态代理使用java的代理机制(JDK动态代理),只能面向接口(由Proxy.newProxyInstance()第二个参数能说明这一点),对接口中的所有方法自动加入代理功能,并且不会干扰原有的业务逻辑代码,因此比较常用;
C. 由于java的动态代理只能面向接口,某些时候项目的业务类不需要接口,而静态代理的诸多不便,怎么办呢?
使用cglib第三方jar包,cglib采用底层的字节码技术,为代理对象创建一个子类,在子类中采用方法拦截技术,拦截父类方法的调用,并织入通用业务功能(面向类的动态代理),但是加载导入的cglib包耗时间,cglib在创建动态代理对象时所花费的时间比 jdk要多(8倍),但是,cglib所创建的动态代理对象的性能比jdk所创建的动态代理对象的性能高很多(10倍左右),对于单例模式对象的代理或者具有实例池(类似于数据库连接池、线程池)的代理,因为不需要频繁创建代理对象,所以适用cglib动态代理;频繁创建代理对象的情况适合用jdk动态代理。