Java靜態代理和動態代理

前言

  • 動態代理在Java中有着廣泛的應用,比如Spring AOP、Mybatis、RPC遠程調用、Java註解對象獲取、日誌、用戶鑑權、全局性異常處理、性能監控,甚至事務處理等。

代理模式

  • 代理模式是給某一個對象提供一個代理,並由代理對象來控制對真實對象的訪問
  • 代理模式根據Java字節碼創建的時機劃分爲靜態代理和動態代理

靜態代理

  • 靜態代理也就是在程序運行前就已經存在代理類的字節碼文件,代理類和真實主題角色的關係在運行前就確定了
  • 代理類
public class StaticProxy {

    private  UserMapper target;

    public StaticProxy(UserMapper mapper)
    {
        this.target =mapper;
    }

    public List<Pojo> select()
    {
        before();
        List<Pojo> res= target.select();
        after();
        return  res;
    }

    public void before(){
        System.out.print(String.format("Load start:[%s]\r\n", new Date().toString()));
    }

    public void after() {
        System.out.print(String.format("Load end:[%s]\r\n", new Date().toString()));
    }
}
  • 測試類
@Service
@Transactional
@Component
public class TestFunc {

    @Autowired
    private UserMapper oMapper;

    @PostConstruct
    private  void test()
    {
        System.out.print("Load data from db start \r\n");

        StaticProxy proxy = new StaticProxy(oMapper);

        List<Pojo> results = proxy.select();
        //List<Pojo> results = oMapper.select();
    }
  • 代理類實際上是目標對象的增強類

靜態代理的缺點

  • 雖然沒有入侵實體類,但是實現目標類的多個接口,導致代理類過大
  • 目標類的修改都要同步修改代理類,耦合嚴重

動態代理

  • 動態代理的源碼是在程序運行期間由JVM根據反射等機制動態的生成,所以在運行前並不存在代理類的字節碼文件
  • 代理類
public class MapperProxy implements InvocationHandler {

    private  Object target;

    public MapperProxy(Object target){
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(target, args);
        after();
        return obj;
    }

    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    private void before(){
        System.out.print(String.format("Load start:[%s]\r\n", new Date().toString()));
    }

    private void after() {
        System.out.print(String.format("Load end:[%s]\r\n", new Date().toString()));
    }
}
  • 測試類
    @Autowired
    private UserMapper oMapper;

    @PostConstruct
    private  void test()
    {
        System.out.print("Load data from db start \r\n");

        MapperProxy proxy = new MapperProxy(oMapper);
        UserMapper mapper = proxy.getProxy();
        mapper.select();

        //List<Pojo> results = oMapper.select();
    }

動態代理的劃分

  • 接口級別代理:JDK動態代理,動態代理類實現InvocationHandler接口
  • 方法級別代理:Cglib代理,在內存中構建一個子類對象從而實現對目標對象功能的擴展
  • 如果是一個對象的 一個或多個接口,可以使用JDK動態代理;如果目標類沒有接口,可以使用Cglib代理實現

動態代理的優點

  1. 解決了靜態代理中冗餘的代理實現類問題。

  2. 系統擴展性和維護性增強。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章