静态代理
概念:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
优点:代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)
缺点:
1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
public interface Person{
public void house();
}
public class Leishuai implements Person{
public void house(){
System.out.println("刚到上海准备去找房子.......");
}
}
// 代理对象
public class StaticProxy implements Person {
private Leishuai leishuai;
public StaticProxy(Leishui leishuai){
this.leishuai = leishuai;
}
public void house(){
System.out.println("你好欢迎来到中介......");
leishuai.house();
Sytem.out.println("走带你去看房子");
}
public static void main(String[] args){
Leishuai leishuai = new Leishuai();
StaticProxy staticproxy = new StaticProxy();
staticproxy.house();
}
}
动态代理:
概念:在程序运行时运用反射机制动态创建而成
优点:动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。
总结:
纵观静态代理与动态代理,它们都能实现相同的功能,而我们看从静态代理到动态代理的这个过程,我们会发现其实动态代理只是对类做了进一步抽象和封装,使其复用性和易用性得到进一步提升而这不仅仅符合了面向对象的设计理念,其中还有AOP的身影,这也提供给我们对类抽象的一种参考。关于动态代理与AOP的关系,个人觉得AOP是一种思想,而动态代理是一种AOP思想的实现!
public interface Person{
void play();
void eat(String sth);
}
public class ZhangSan implements Person{
public void play(){
System.out.println("s9 四强......");
}
public void eat(){
System.out.println("吃......"+鱼);
}
}
public class CalculatorLogProxy{
public static void main(String[] args){
// 要被代理的目标对象
Person p = new ZhangSan();
/**
* 第一个参数:被代理对象的类加载器
* 第二个参数:被代理对象实现的所有接口
* 第三个参数:用来对被代理对象进行增强的核心接口
*/
Person calculator = (Person)Proxy.newProxyInstance(p.getClass().getClassLoader(),p.getClass().getInterfaces(),new InvocationHandler(){
/**
* 增强方法的核心方法
* @param proxy 代理对象
* @param method 通过反射生成的代理对象的方法
* @param args 被增强方法的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object invoke;
String name = method.getName();
if(name.equals("eat")){
System.out.println("你准备吃什么...........");
invoke = method.invoke(p,args);
System.out.println("我帮你去准备...........");
}else{
System.out.println("我会帮你物色好战队的.........");
invoke = method.invoke(p,args);
System.out.println("有一个战队很适合你...........");
}
return invoke;
}
});
calculator.eat("羊肉");
calculator.play();
}
}
断点分析 :
public class ZhangSan {
public void play(){
System.out.println("s9 四强......");
}
public void eat(){
System.out.println("吃......"+鱼);
}
}
// cglib动态代理
public class CglibProxy {
public static Object getCglibProxy(Object target){
// 该类是实现增强类的核心
Enhancer enhancer = new Enhancer();
// 设置被代理的对象
enhancer.setSuperclass(target.getClass());
// 设置增强
enhancer.setCallback(new MethodInterceptor(){
/**
* @param proxy 代理对象
* @param method 要被代理对象的方法
* @param objects 要被代理对象的参数
* @param methodProxy 通过反射生成代理方法的代理对象
* @return
* @throws Throwable
*/
public Object intercept(Object proxy,Method method,Object[] args,MethodProxy methodProxy) throws Throwable{
System.out.println("before");
Object invokerSupper = methodProxy.invokeSuper(proxy,args);
System.out.println("after");
return invokerSupper;
}
});
return enhancer.create();
}
public static void main(String[] args){
ZhangSan zs = new ZhangSan();
ZhangSan cglib = (ZhangSan)CglibProxy.getCglibProxy(zs);
cglib.play();
}
}
断点分析 :
jdk动态代理和cglib动态代理
jdk:是根据目标对象的接口生成的一个实现类,这个实现类实现了目标对象的所有接口
优点:使用灵活,可以方便的进行的后期的维护和升级
缺点:需要接口,如果没有接口,就无法使用jdk动态代理
cglib:是通过对某个具体的类型,生成的一个子类,然后进行功能增强
优点:在没有接口的情况下(在有接口的情况也可以生成代理对象),同样可以实现类的增强
缺点:需要程序员自行实现全部代理过程