您当前的位置: 首页 >  Java

cuiyaonan2000

暂无认证

  • 2浏览

    0关注

    248博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java Proxy

cuiyaonan2000 发布时间:2022-05-24 10:27:18 ,浏览量:2

序言

给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。

如果根据字节码的创建时机来分类,可以分为静态代理和动态代理:

  • 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
  • 而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件

参考资料:

  1. 深入理解Java动态代理 - 知乎
  2. 【动态代理】InvocationHandler_点不点外卖的博客-CSDN博客_invocationhandler

静态代理

静态代理模式很容易理解.即代理类与被代理类都需要实现同一个接口cuiyaonan2000@163.com

package cui.yao.nan.optional;

import java.util.Optional;
import java.util.Random;

/**
 * @Author: cuiyaonan2000@163.com
 * @Description: todo
 * @Date: Created at 2022-1-12  14:46
 */
public class Test {

    public interface Vehicle{
        public void run();
    }

    public class Car implements  Vehicle{

        private String name;

        @Override
        public void run() {
            System.out.println(" my name is :" + name);
        }

        public Car(String name) {
            this.name = name;
        }
    }

    public class CarProxy implements  Vehicle{

        private Car car;

        @Override
        public void run() {
            car.run();
        }

        public CarProxy(String name) {
            this.car = new Car(name);
        }
    }

    public static void main(String[] args){
        Vehicle vehicle = new Test().new CarProxy("三轮车");
        vehicle.run();

    }
}

动态代理

java根据代理类的实现主要区分如下的两种方式:

  1. 通过实现接口的方式 : JDK动态代理
  2. 通过继承类的方式 :CGLIB动态代理

JDK动态代理

被代理类需要实现业务接口,代理类需要实现接口InvocationHandler. 然后通过Proxy来生成代理类

InvocationHandler

该接口在反射包下.且只有一个接口方法.该方法就是用于对目标对象的方法进行增强的.

/*
 * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.lang.reflect;

/**
 * {@code InvocationHandler} is the interface implemented by
 * the invocation handler of a proxy instance.
 *
 * 

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} * method of its invocation handler. * * @author Peter Jones * @see Proxy * @since 1.3 */ public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }

Proxy

同理也是在反射包中(java.lang.reflect)

该类是用于动态生成代理类(注意这的动态生成,是在项目启动的时候生成一个class类cuiyaonan2000@163.com)

具体使用如下的方法来生成一个代理类,生成的代理类可以保存在本地哦~~~~~ 

保存代理类

//在生成代理类的环境中设置如下的配置
//则会将生成的代理类保存在,本地名字默认名称以 $Proxy0 格式命名
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

或者使用代码保存

package cui.yao.nan.optional;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author: cuiyaonan2000@163.com
 * @Description: todo
 * @Date: Created at 2022-5-24  9:24
 */
public class Test2 {


    public interface Vehicle{
        public void run();
    }

    public class Car implements Vehicle{
        public void run(){
            System.out.println("i am a car");
        }
    }

    public class ProxyHandle implements InvocationHandler{
        private Object object;

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("proxy:"+proxy.getClass().getName());
            System.out.println("method:"+method.getName());
//            System.out.println("args:"+args[0].getClass().getName());

            System.out.println("Before invoke method...");
            Object result=method.invoke(this.object,args);
            System.out.println("After invoke method...");

            return result;
        }

        public ProxyHandle(Object object) {
            this.object = object;
        }
    }




    public static void main(String[] args){
        Car car = new Test2().new Car();
        InvocationHandler invocationHandler = new Test2().new ProxyHandle(car);
        Vehicle vechicle = (Vehicle) Proxy.newProxyInstance(car.getClass().getClassLoader(),car.getClass().getInterfaces(),invocationHandler);
        vechicle.run();


        // 根据类信息和提供的代理类名称,生成字节码
        byte[] classFile = ProxyGenerator.generateProxyClass( "jjj", new Class[]{car.getClass()});
        String paths = car.getClass().getResource(".").getPath();
        System.out.println(paths);
        FileOutputStream out = null;
        try {
            //保留到硬盘中
            out = new FileOutputStream(paths + "jjj" + ".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch ( IOException e) {
                e.printStackTrace();
            }
        }
    }
}

CGLIB动态代理

CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,来完成动态代理的实现。实现方式实现 MethodInterceptor 接口,重写 intercept 方法,通过 Enhancer 类的回调方法来实现。但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。

CGLIB动态代理就是对指定的类生成一个子类,覆盖其中所有的方法并环绕增强.所以被代理类的方法如果是final 修饰的就不能进行代理cuiyaonan2000@163.com

Spring已经集成了CGLIB的相关库,所以引入如下的即可

  
            org.springframework
            spring-core
        

实例

package cui.yao.nan.optional;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Author: cuiyaonan2000@163.com
 * @Description: todo
 * @Date: Created at 2022-5-24  9:24
 */
public class Test2 implements MethodInterceptor{

    public Test2() {
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before you method running");
        return method.invoke(o,objects);
    }

    public class MyInterceptor implements MethodInterceptor {

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("before you method running");
            return method.invoke(o,objects);
        }

    }


    public static void main(String[] args){

        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(Car.class);

        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before you method running");
                Object result = methodProxy.invokeSuper(o, objects);
                System.out.println("after you method running");
                return result;
            }
        });

        Car car =(Car)enhancer.create();

        car.run();

    }
}

关注
打赏
1638267374
查看更多评论
立即登录/注册

微信扫码登录

0.0369s