91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 動態代理的理解與Cglib動態代理實現

發布時間:2020-06-12 12:22:57 來源:網絡 閱讀:538 作者:nineteens 欄目:編程語言

  什么是動態代理?

  先說下靜態代理:

  也即是說,在程序運行前,已經有了編譯好的類,這個就是靜態代理,

  動態代理:

  也即,在程序運行前, 代理類并不存在,而是在程序運行時,動態生成的類是動態代理類。

  可能會有如下思考

  代理模式是怎樣的?用什么技術實現?

  為什么要使用代理模式呢?有什么好處?

  動態代理的應用場景有哪些?

  先說說動態代理的實現吧:

  動態代理主要使用的是Java 反射技術:

  JavaAPI 中關于InvocationHandler有大致這么一段描述,每個代理類都要實現InvocationHandler這個接口,每個代理類都會關聯到一個handle,

  當一個代理類調用方法時,會轉到InvocationHandler的Invoke方法進行調用。

  以下代碼有引用以為牛人代碼

  看下InvocationHandler源碼,我這就不再寫一遍了。

  public interface InvocationHandler

  {

  public abstract Object invoke(Object obj, Method method, Object aobj[])

  throws Throwable;

  }

  這個invoke方法中有幾個參數 :

  obj:表示我們要調用的真實對象

  method:表示我們要調用的真實對象的某個方法。

  aobj[] :表示真實對象某個方法接受的參數。

  怎么用這個InvocationHandler 這個接口,主要看proxy這個類:

  Proxy是創建一個代理對象的類

  Proxy這個類有這個一個方法:是用的最多的方法

  public static Object newProxyInstance(ClassLoader classloader, Class aclass[], InvocationHandler invocationhandler)

  throws IllegalArgumentException

  參數:

  classloader: 定義了由那個ClassLoader對對象進行加載

  aclass[]: 是為代理對象提供了哪些接口,表示代理對象實現了這些接口,

  invocationhandler: 表示代理對象調用方法時會關聯到那個invocationhandler

  主要通過類Proxy與接口invocationhandler實現動態代理:

  看下具體動態代理實現加深理解:

  1.首先肯定是需要一個接口的:

  public interface UserService {

  public String getName(int id);

  public Integer getAge(int id);

  }

  還需要這個接口的實現,也就是代理對象:

  public class UserServiceImpl implements UserService {

  @Override

  public String getName(int id) {

  System.out.println("------getName------");

  return "Tom";

  }

  @Override

  public Integer getAge(int id) {

  System.out.println("------getAge------");

  return 10;

  }

  }

  還需要自定義一個invocationhandler ,自己實現invoke方法:

  import java.lang.reflect.InvocationHandler;

  import java.lang.reflect.Method;

  public class MyInvocationHandler implements InvocationHandler {

  private Object target;

  MyInvocationHandler() {

  super();

  }

  MyInvocationHandler(Object target) {

  super();

  this.target = target;

  }

  @Override

  public Object invoke(Object o, Method method, Object[] args) throws Throwable {

  if("getName".equals(method.getName())){

  System.out.println("++++++before " + method.getName() + "++++++");

  Object result = method.invoke(target, args);

  System.out.println("++++++after " + method.getName() + "++++++");

  return result;

  }else{

  Object result = method.invoke(target, args);

  return result;

  }

  }

  }

  最后再看下proxy是怎樣的使用這個接口,還有invocationhandler的

  import java.lang.reflect.InvocationHandler;

  import java.lang.reflect.Proxy;

  public class TestProxy {

  public static void main(String[] args) {

  UserService userService = new UserServiceImpl();

  InvocationHandler invocationHandler = new MyInvocationHandler(userService);

  UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),

  userService.getClass().getInterfaces(), invocationHandler);

  System.out.println(userServiceProxy.getName(1));

  System.out.println(userServiceProxy.getAge(1));

  }

  }

  以上可以看到可以清晰理解proxy的newproxyInstance是用來生成代理對象的, userService是指向具體 的實現

  UserServiceImpl

  給newproxyInstance方法傳入實際的classLoader,實際類對應的接口,與調用類方法的invocationhandler即可實現:

  System.out.println("++++++before " + method.getName() + "++++++");

  其實上面這個一行代碼就有***性質,aop時再詳細討論.

  上面可以看到 使用這個反射技術實現動態代理,需要定義一個接口,但是有時候其實不想定義接口,只希望定義好實現類,然后你再在方法運行前,運行后加些內容即可。

  這個就考慮了一個CGLIB這個可是不錯的使用CGLIB實現動態代理很方便。

  Cglib 采用的是ASM字節碼技術,利用字節碼生成代理類。效率比反射要高,但是不能代理final修身的類,clglib元素是集成被代理的類。final類不能被繼承。

  下面看下cglib具體實現:

  下載 cglib包和asm包,你的工程需要依賴這兩個包:

  首先需要一個非final類,不再和反射一樣需要一個接口了

  public class StudentService {

  public String getName(){

  System.out.println("------getName------");

  return "Tom";

  }

  public Integer getID(){

  System.out.println("------getID------");

  return 10;

  }

  }

  接下來就看怎么代理上面的類了,需要定義一個攔截器:

  import net.sf.cglib.proxy.MethodInterceptor;

  import net.sf.cglib.proxy.MethodProxy;

  import java.lang.reflect.Method;

  public class CglibProxy implements MethodInterceptor {

  @Override

  public Object intercept(Object o, Method method, Object[] args,

  MethodProxy methodProxy) throws Throwable {

  System.out.println("++++++before " + methodProxy.getSuperName()

  + "++++++");

  System.out.println(method.getName());

  Object o1 = methodProxy.invokeSuper(o, args);

  System.out.println("++++++before " + methodProxy.getSuperName()

  + "++++++");

  return o1;

  }

  }

  上面的interceptf方法和invocationhandler中的invoke方法類似,通過interceptf來真正調用方法invokeSuper:

  最后看下Cglb具體怎么代理StudentService這個類吧:

  import net.sf.cglib.proxy.Enhancer;

  public class TestCglib {

  public static void main(String[] args) {

  CglibProxy cglibProxy = new CglibProxy();

  Enhancer enhancer = new Enhancer();

  enhancer.setSuperclass(StudentService.class);

  enhancer.setCallback(cglibProxy);

  StudentService o = (StudentService)enhancer.create();

  System.out.println(o.getName());

  // System.out.println(o.getID());

  }

  }

  上面的o即是 代理類,該類可以訪問真實的Studentservice方法:

  運行結果:無錫婦科檢查多少錢 http://www.120csfkyy.com/

  ++++++before CGLIB$getName$1++++++

  getName

  ------getName------

  ++++++before CGLIB$getName$1++++++

  Tom

  使用Cglib 有啥好處?

  看下面代碼:

  public class TestCglib {

  public static void main(String[] args) {

  CglibProxy cglibProxy = new CglibProxy();

  Enhancer enhancer = new Enhancer();

  enhancer.setSuperclass(StudentService.class);

  enhancer.setCallback(cglibProxy);

  StudentService o = (StudentService)enhancer.create();

  System.out.println(o.getName());

  // System.out.println(o.getID());

  Enhancer enhancer1 = new Enhancer();

  enhancer1.setSuperclass(UserServiceImpl.class);

  enhancer1.setCallback(cglibProxy);

  UserServiceImpl obj = (UserServiceImpl)enhancer1.create();

  System.out.println(obj.getName(1));

  // System.out.println(o.getID());

  }

  }

  只要寫一個

  cglibProxy

  就可以是實現

  對UserServiceImpl 與 StudentService進行代理

  減少了代碼的繁瑣,只有有這么一個代理就夠了,其次方便維護,解耦合,要是有問題,只要去找 原始類就可以了


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

关岭| 汉中市| 丹东市| 黄大仙区| 阜阳市| 浦东新区| 城固县| 嘉定区| 犍为县| 普陀区| 崇阳县| 兴安盟| 阿坝县| 离岛区| 泗水县| 喜德县| 台湾省| 开鲁县| 西昌市| 九寨沟县| 文山县| 嘉峪关市| 吉木萨尔县| 应用必备| 万宁市| 石泉县| 霍林郭勒市| 临汾市| 犍为县| 阜南县| 大厂| 石嘴山市| 中卫市| 平度市| 五常市| 邮箱| 新兴县| 孝感市| 顺义区| 长乐市| 韶关市|