zoukankan      html  css  js  c++  java
  • 静态代理,jdk动态代理,cglib动态代理

    代理模式:是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

    示例:火车票代售就是代理模式的体现,我们可以从火车票代售点买火车票,代售点代理了火车站对象,提供了买火车票的方法

     

     一:静态代理

    • 前提:需要代理对象和目标对象实现一样的接口
    • 优点:可以在不修改目标对象的前提下,扩展目标对象的功能
    • 缺点:如果目标对象的方法发生改变,比如方法名做了修改,则代理类也要做修改
    /**
     * 接口
     * @author Ethon
     *
     */
    public interface Person {
    
        void add();
    
    }
    /**
     * 目标对象
     * @author Ethon
     *
     */
    public class Student implements Person {
        
        @Override
        public void add() {
                System.out.println("这是目标对象中的add()方法");
        }
    }
    /**
     * 代理对象
     * @author Ethon
     *
     */
    public class StudentProxy implements Person{
        
        //目标对象
        private Student student;
        
        public StudentProxy(Student student){
            this.student = student;
        }
    
        @Override
        public void add() {
            System.out.println("开启事务..."); // 扩展功能
            student.add();
            System.out.println("提交事务...");
        }
    }
    /**
     * 测试类
     * @author Ethon
     *
     */
    public class Test {
        
        public static void main(String[] args){
            //目标对象
            Student student = new Student();
            //代理对象
            StudentProxy proxy = new StudentProxy(student);
            proxy.add();
        }
    }

    输出结果:

    开启事务...
    这是目标对象中的add()方法
    提交事务...

     ----------------------------------------------------------  分隔线  ----------------------------------------------------------

    二、动态代理

    代理类在程序运行时创建的代理方式被成为动态代理,动态代理对象不需要实现接口,但目标对象必须实现接口。

           静态代理与动态代理的区别:

    • 静态代理在编译时就已经实现,编译完成后代理类就是一个实际的class文件
    • 动态代理在运行时动态生成字节码,并加载到jvm中

    JDK的动态代理:在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。

    /**
     * 接口
     * @author Ethon
     *
     */
    public interface Person {
    
        void add();
    
    }
    /**
     * 目标对象
     * @author Ethon
     *
     */
    public class Student implements Person {
        
    
        @Override
        public void add() {
                System.out.println("这是目标对象中的add()方法");
        }
    }
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * @author Ethon
     *
     */
    public class StuInvocationHandler implements InvocationHandler{
        //目标对象
        private Object target;
        
        public StuInvocationHandler(Object target){
            this.target = target;
        }
    
        /**
         * proxy: 动态代理对象
         * method:正在执行的方法
         * args:调用目标方法时传入的实参
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("开启事务..."); // 扩展功能
            Object obj = method.invoke(target, args);
            System.out.println("提交事务...");
            return obj;
        }
    }
    /**
     * 测试类
     * @author Ethon
     *
     */
    public class Test {
        
        public static void main(String[] args){
            //目标对象
            Person student = new Student();
            //创建一个与代理对象相关联的InvocationHandler
            InvocationHandler handler = new StuInvocationHandler(student);
            //得到代理对象
            Person studentProxy = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), handler);
            studentProxy.add(); 
        }
    }

    输出结果:

    开启事务...
    这是目标对象中的add()方法
    提交事务...

    ----------------------------------------------------------  分隔线  ----------------------------------------------------------

     cglib的动态代理:CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法。

    /**
     * 业务类
     * @author Ethon
     *
     */
    public class Student {
        
        /**
         * 该方法不能被子类覆盖,cglib是无法代理final修饰的方法的
         */
        final public void sing(){
            System.out.println("sing...");
        }
    
        public void study(){
            System.out.println("study...");
        }
    }
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    /**
     * 方法拦截器
     * @author Ethon
     *
     */
    public class MyMethodInterceptor implements MethodInterceptor{
    
        /**
         * obj:表示增强的对象,即实现这个接口类的一个对象
         * method:表示要被拦截的方法
         * args:表示要被拦截方法的参数
         * proxy:表示要触发父类的方法对象
         */
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("开启事务..."); //扩展功能
            Object object = proxy.invokeSuper(obj, args);
            System.out.println("提交事务...");
            return object;
        }
    }
    import net.sf.cglib.core.DebuggingClassWriter;
    import net.sf.cglib.proxy.Enhancer;
    
    /**
     * 测试类
     * @author Ethon
     *
     */
    public class Test {
        public static void main(String[] args){
            //代理类class文件存入本地磁盘
            //System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D\code");
            //通过cglib动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            //设置enhancer对象的父类
            enhancer.setSuperclass(Student.class);
            //设置enhancer的回调对象
            enhancer.setCallback(new MyMethodInterceptor());
            //创建代理对象
            Student stuProxy = (Student) enhancer.create();
            //通过代理对象调用目标方法
            //调用方法时,在代理类中会先判断是否实现了方法拦截的接口,如果实现了那就会被方法拦截器拦截,没实现的话直接调用目标类的方法
            stuProxy.study();
        }
    }

    输出结果:

    开启事务...
    study...
    提交事务...

  • 相关阅读:
    mybatis遍历map
    程序员开发思考-1
    linux shell学习-1
    IDEA tomcat部署
    理解TCP/IP协议
    winform实现自定义折叠面板控件
    目录特殊符号导致的应用程序处于中断模式
    Vue-element-admin实现菜单根据用户权限动态加载
    基于EF的一个简单实战型分层架构
    Linux开启SELinux的情况下怎么解决nginx403跟502错误
  • 原文地址:https://www.cnblogs.com/wakey/p/13974565.html
Copyright © 2011-2022 走看看