zoukankan      html  css  js  c++  java
  • java中动态代理的实现

    动态代理的实现

    使用的模式:代理模式。
    代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。类似租房的中介。

    两种动态代理:
    (1)jdk动态代理,jdk动态代理是由Java内部的反射机制来实现的,目标类基于统一的接口(InvocationHandler)
    (2)cglib动态代理,cglib动态代理底层则是借助asm来实现的,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

    主要应用的框架:
    Spring中的AOP,Struts2中的拦截器

    具体实现:


    1、定义接口和实现类

    package com.example.service;
    
    public interface UserService {
        public String getName(int id);
    
        public Integer getAge(int id);
    }
    package com.example.service.impl;
    
    import com.example.service.UserService;
    
    public class UserServiceImpl implements UserService {
    
        public String getName(int id) {
            System.out.println("------getName------");
            return "cat";
        }
    
        public Integer getAge(int id) {
            System.out.println("------getAge------");
            return 10;
        }
    }

    2、jdk动态代理实现

    package com.example.jdk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    
    public class MyInvocationHandler implements InvocationHandler {
        private Object target;
    
        /**
         * 绑定委托对象并返回一个代理类
         *
         * @param target
         * @return
         */
        public Object bind(Object target) {
            this.target = target;
            //取得代理对象
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
        }
    
        @Override
        public Object invoke(Object proxy, 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;
            }
        }
    }
    package com.example.jdk;
    
    import com.example.service.UserService;
    import com.example.service.impl.UserServiceImpl;
    
    /**
     * 测试类
     */
    public class RunJDK {
    
        public static void main(String[] args) {
            MyInvocationHandler proxy = new MyInvocationHandler();
            UserService userServiceProxy = (UserService) proxy.bind(new UserServiceImpl());
            System.out.println(userServiceProxy.getName(1));
            System.out.println(userServiceProxy.getAge(1));
        }
    }

    运行结果:
    ------before getName------
    ------getName------
    ------after getName------
    cat
    ------getAge------
    10

    3、cglib动态代理实现:

    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

    CGLIB的核心类:
    net.sf.cglib.proxy.Enhancer – 主要的增强类
    net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
    net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用。

    net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
    public Object intercept(Object object, java.lang.reflect.Method method,
    Object[] args, MethodProxy proxy) throws Throwable;

    第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。

    package com.example.cglib;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class CGLIBProxy implements MethodInterceptor {
        private Object target;
    
        /**
         * 创建代理对象
         *
         * @param target
         * @return
         */
        public Object getInstance(Object target) {
            this.target = target;
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(this.target.getClass());
            // 回调方法
            enhancer.setCallback(this);
            // 创建代理对象
            return enhancer.create();
        }
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");
            System.out.println(method.getName());
            Object result = methodProxy.invokeSuper(o, objects);
            System.out.println("++++++after " + methodProxy.getSuperName() + "++++++");
    
            return result;
        }
    }
    package com.example.cglib;
    
    import com.example.service.UserService;
    import com.example.service.impl.UserServiceImpl;
    
    /**
     * 测试CGLIB
     */
    public class RunCGLIB {
    
        public static void main(String[] args) {
            CGLIBProxy cglibProxy = new CGLIBProxy();
            UserService userService = (UserService) cglibProxy.getInstance(new UserServiceImpl());
            userService.getName(1);
            userService.getAge(1);
        }
    }
    运行结果:
    ++++++before CGLIB$getName$0++++++
    getName
    ------getName------
    ++++++after CGLIB$getName$0++++++
    ++++++before CGLIB$getAge$1++++++
    getAge
    ------getAge------
    ++++++after CGLIB$getAge$1++++++
  • 相关阅读:
    Spring boot unable to determine jdbc url from datasouce
    Unable to create initial connections of pool. spring boot mysql
    spring boot MySQL Public Key Retrieval is not allowed
    spring boot no identifier specified for entity
    Establishing SSL connection without server's identity verification is not recommended
    eclipse unable to start within 45 seconds
    Oracle 数据库,远程访问 ora-12541:TNS:无监听程序
    macOS 下安装tomcat
    在macOS 上添加 JAVA_HOME 环境变量
    Maven2: Missing artifact but jars are in place
  • 原文地址:https://www.cnblogs.com/xiarongjin/p/8522542.html
Copyright © 2011-2022 走看看