• jdk动态代理与cglib动态代理例子


    1.JAVA的动态代理特征:特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

    它是在运行是生成的class对象,在生成时必须提供一组或一个interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当做这些interface中的任何一个来用,当然,这个DynamicProxy其实就是一个Proxy,他不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。因此,DynamicProxy必须实现InvocationHandler接口。
    5) 一个动态代理了和一个InvocationHandler 实现关联的。每一个动态代理实例的调用都要通过InvocationHandler接口的handler(调用处理器)来调用,动态代理不做任何执行操作,只是在创建动态代理时,把要实现的接口和handler关联,动态代理要帮助被代理执行的任务,要转交给handler来执行。其实就是调用invoke方法

    动态代理:在程序运行时,运用反射机制动态创建而成

    2.实用动态代理步骤:

    A. 创建一个实现接口InvocationHandler的类,他必须实现invoke方法
    B. 创建被代理的类以及接口。
    C. 通过Proxy的静态方法newProxyInstance(ClassLoader loader,Class【】interfaces,InvocationHandler handler)创建一个代理
    D. 通过代理调用方法

    3.jdk动态代理例子:

    文件列表:

    业务接口:UserService

    业务实现:UserServiceImpl

    代理类的调用Handler实现:ProxyHandler

    JUnit测试类:SpringProxyTest

    package com.niewj.service;

    import com.niewj.model.User;

    public class UserServiceImpl implements UserService {

     @Override
     public void add(User user) {
      System.out.println("User Saved. & ");
     }

     @Override
     public void delete(User user) {
      System.out.println("User Deleted. &");
     }
    }

    package com.niewj.service;

    import com.niewj.model.User;

    public class UserServiceImpl implements UserService {

     @Override
     public void add(User user) {
      System.out.println("User Saved. & ");
     }

     @Override
     public void delete(User user) {
      System.out.println("User Deleted. &");
     }
    }

    package com.niewj.service;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;

    /**
     * JDK动态代理模拟
     *
     * 1.首先明确什么是目标对象target,什么是代理对象proxy!!
     *
     * 2.每个代理对象对象都会有一个相关的InvocationHandler对象。
     * 当代理对象生成的时候,是创建的代理对象,
     * 拿着相关的这个InvocationHandler对象,去自动调Handler类中实现的invoke方法的。
     * 下面一段话来自@javadoc@
     * <p>Each proxy instance has an associated invocation handler.
     * When a method is invoked on a proxy instance, the method
     * invocation is encoded and dispatched to the <code>invoke</code>
     * method of its invocation handler.
     *
     * 3.还有就是我发现,我的Eclipse控制台TMD输出的顺序有误,害的老以为我人品出了什么问题,
     * 不知道控制台的信息是不是不是栈式输出的。(好绕口)
     *
     */
    public class ProxyHandler implements InvocationHandler {

     // 就是要给这个目标类创建代理对象。
     private Object target;

     // 传递代理目标的实例,因为代理处理器需要。也可以用set等方法。
     public ProxyHandler(Object target) {
      this.target = target;
     }

     /*
      * 这个方法是给代理对象调用的。
      * 留心的是内部的method调用的对象是目标对象,可别写错。
      */
     @Override
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {
      Object ret = null;
      // 1.调用前
      cutIntoBefore(method.getName());

      ret = method.invoke(target, args);

      // 2.调用后
      cutIntoAfter(method.getName());
      return ret;
     }

     public void cutIntoBefore(String mName) {
      System.err.println("调用____" + mName + "()____方法之前");
     }

     public void cutIntoAfter(String mName) {
      System.err.println("调用____" + mName + "()____方法完后");
     }
    }

    package com.niewj;

    import java.lang.reflect.Proxy;

    import org.junit.Test;

    import com.niewj.model.User;
    import com.niewj.service.ProxyHandler;
    import com.niewj.service.UserService;
    import com.niewj.service.UserServiceImpl;

    public class SpringProxyTest {

     @Test
     @SuppressWarnings("rawtypes")
     public void testJDKDynamicProxy() {

      /* 1.获取UserServiceImpl对象--目标对象--也就是需要被代理的对象。 */
      UserService userService = new UserServiceImpl();
      // 获取当前类名
      Class clazz = userService.getClass();
      /*
       * 2.获得代理对象。
       * 每一个代理对象都有一个相关的InvocationHandler对象,通过这个handler对象的invoke来实现调用中要完成的自定义猫腻行为
       * 。 可以使用Proxy类和自定义的调用处理逻辑来生成一个代理对象的。
       */
      UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
        clazz.getClassLoader(), clazz.getInterfaces(),
        new ProxyHandler(userService));
      userServiceProxy.add(new User("dotjar"));
      userServiceProxy.delete(new User("DDD"));
     }
    }

    4.cglib动态代理

    JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。

    它的运行速度要远远快于JDKProxy动态代理。

    使用CGLIB需要导入以下两个jar文件:

        asm.jar – CGLIB的底层实现。

        cglib.jar – CGLIB的核心jar包。

    例子:

    package com.niewj.service;

    import java.lang.reflect.Method;

    import com.niewj.model.User;

    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;

    public class CgLibProxyImitation implements MethodInterceptor {

     private Enhancer enhancer = new Enhancer();

     /** 创建代理对象
      * @param targetClass
      * @return 返回代理对象
      */
     @SuppressWarnings("rawtypes")
     public Object getProxy(Class targetClass) {
      enhancer.setSuperclass(targetClass); //设置需要创建子类的类
      enhancer.setCallback(this);
      return enhancer.create(); //通过字节码技术动态创建子类实例

     }

     public void cutIntoBefore(String mName) {
      System.err.println("调用____" + mName + "()____方法之前");
     }

     public void cutIntoAfter(String mName) {
      System.err.println("调用____" + mName + "()____方法完后");
     }

     /*  生成的代理对象调用此对象来替代原始对象
      *
      * @java.lang.Object 增强对象
      * @java.lang.reflect.Method 拦截方法
      * @java.lang.Object[] 参数数组
      * @net.sf.cglib.proxy.MethodProxy  用于调用父类,按需要调用多次
      */
     @Override
     public Object intercept(Object obj, Method method, Object[] args,
       MethodProxy proxy) throws Throwable {
      cutIntoBefore(method.getName());
      Object result = proxy.invokeSuper(obj, args);
      cutIntoAfter(method.getName());
      return result;
     }
     
     public static void main(String[] args) {
    //  UserService userService = new UserServiceImpl();
      CgLibProxyImitation cglib = new CgLibProxyImitation();
      UserServiceImpl userService = (UserServiceImpl)cglib.getProxy(UserServiceImpl.class);
      userService.add(new User("dotjar"));
      userService.delete(new User("hill"));
     }
    }

  • 相关阅读:
    linux操作系统及内核
    2.1.1Remove Duplicates from Sorted Arr
    顺序表
    开博篇
    ssh无法root用户登录与登录界面无法选择用户登录
    Ubuntu 18.04 Server安装GUI桌面
    Linux 命令 su 和 sudo 区别
    坑(二十六)—— mysql出现ERROR1698(28000):Access denied for user root@localhost错误解决方法
    redhat安装wps
    gitlab重置root密码
  • 原文地址:https://www.cnblogs.com/qqzy168/p/3150700.html
Copyright © 2020-2023  润新知