`

java代理之静态和动态

    博客分类:
  • java
阅读更多

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动态代理。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics