2020-12-31

java动态代理

代理的核心思想是横切,在垂直业务中横切进去与业务无关的代码(比如日志),使业务代码更加纯粹的只专注于本身(AOP是基于代理模式)

静态代理

模拟房东出售房屋的场景

//接口主要起到约束的作用,出租房屋
public interface RentHouse {
     
    void rentHouse();
}
//目标对象  房东
public class Landlord implements RentHouse{
     
    @Override
    public void rentHouse(){
     
        System.out.println("房东出租房屋");
    }
}
//代理对象 中介  中介不仅可以代替房东出售房屋  还可以代替收租
public class Medium implements RentHouse{
     

    private RentHouse rentHouse;

    public Medium(RentHouse rentHouse){
     
        this.rentHouse=rentHouse;
    }

    public void rentCollection(){
     
        System.out.println("收取租金");
    }

    @Override
    public void rentHouse() {
     
        rentCollection();
        rentHouse.rentHouse();
    }
}
//房屋出租
public class HouseService {
     
    public static void main(String[] args) {
     
        //多肽,运行期绑定
        RentHouse rent=new Medium(new Landlord());
        rent.rentHouse();
    }
}

运行结果:
2020-12-31_第1张图片
总结:优点 静态代理实现简单,拆分业务与非业务代码,实现松散耦合

​ 缺点 一个代理对象只能服务于一种类型的对象,如果需要对很多类型对象进行代理,就需要生成等量的代理对象,不易扩展与维护

​ 解决静态代理的缺点就需要使用动态代理,java中动态代理分为jdk的动态代理和cgLib的动态代理,区别是jdk的动态基于接口实现,cgLib的动态代理基于类实现。

动态代理

  • 基于接口实现的jdk动态代理

    在jdk1.3之后加入了可协助开发的动态代理功能,我们不需要再为不同对象去编写不同的代理对象,使用动态代理可以使一个处理者服务于各个对象

    一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口,通过InvocationHandler接口实现的代理类(由Proxy生成代理类)只能代理接口的实现类

    //处理者
    public class ProxyHandler implements InvocationHandler {
           
        //使用Object类接收需要被代理的目标对象
        private Object target;
    
        public void setProxy(Object target){
           
            this.target=target;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           
            rentCollection();//执行切入片段
            Object invoke = method.invoke(target, args);
            return invoke;
        }
    
        public void rentCollection(){
           
            System.out.println("收取租金");
        }
    }
    
    //生成代理对象的工厂
    public class ProxyFactory {
           
        //object为目标对象(被代理的对象)  通过目标对象得到代理对象
        public static Object getProxy(Object object){
           
            ProxyHandler handler=new ProxyHandler();
            handler.setProxy(object);
            /*
              loader - 类加载器来定义代理类
              interfaces - 代理类实现的接口列表
              h - 调度方法调用的调用处理函数
             */
            return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),handler);
        }
    }
    
    //运行结果如上
    public class HouseService {
           
        public static void main(String[] args) {
           
            //jdk动态代理
            RentHouse rent=(RentHouse)ProxyFactory.getProxy(new Landlord());
            rent.rentHouse();
        }
    }
    
  • 基于类实现的cgLib动态代理

2020-12-31_第2张图片

//cgLib实现的动态代理  目标对象不需要实现接口
public class HouseService {
     
    public static void main(String[] args) {
     
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
     
            /*
            参数:obj为由CGLib动态生成的代理类实例,
                  method是实体类中所调用的被代理的方法引用,
                  args为参数值列表,
                  proxy为生成的代理类对方法的代理引用。
            */
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
     
                System.out.println("插入的代码片段");
                //result从代理实例的方法调用返回的值。
                Object result = proxy.invokeSuper(obj, args);
                return result;
            }
        };
        //回调方法过滤  可以选择性的执行回调方法,也可以不执行
        CallbackFilter callbackFilter = new CallbackFilter() {
     
            //过滤方法 返回的值为数字,代表了CallBacks数组中的索引位置
            @Override
            public int accept(Method method) {
     
                if (method.getName().equals("test")) {
     
                    return 1;//对应 methodInterceptor 进入代理对象的方法拦截器
                }
                return 0;//对应 NoOp.INSTANCE 表示过滤器不进行处理
            }
        };
        //FixedValue用来对所有拦截的方法返回相同的值 不会再调用代理目标类的相应方法
        FixedValue fixedValue = new FixedValue() {
     
            @Override
            public Object loadObject() throws Exception {
     
                System.out.println("方法被拦截 不调用代理");
                return null;
            }
        };
        Callback []callbacks={
     NoOp.INSTANCE,methodInterceptor,fixedValue};
        Enhancer enhancer=new Enhancer();
        //设置父类型,因为Enhancer为目标对象创建了一个子类
        enhancer.setSuperclass(SampleClass.class);
        enhancer.setCallbackFilter(callbackFilter);
        enhancer.setCallbacks(callbacks);
        SampleClass proxy=(SampleClass)enhancer.create();
        proxy.test();
    }

    public static class SampleClass {
     
        public void test(){
     
            System.out.println("cgLib");
        }
    }
}

运行结果:2020-12-31_第3张图片

cgLib动态代理相关类:

1. Enhancer

​ Enhancer可能是cgLib中最常用的一个类,和Java1.3动态代理中引入的Proxy类差不多,不同的是Enhancer不仅可以代理接口,也能够代理普通的class

​ Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object类中继承的方法),不能够拦截final方法,(可以这样想吗 因为创建的子类不能继承final方法,所以也就不能够拦截?)

public class TestEnhancer {
     
    public static void main(String[] args) {
     
        Enhancer enhancer=new Enhancer();
        //设置父类型,因为Enhancer为目标对象创建了一个子类
        enhancer.setSuperclass(SampleClass.class);
        enhancer.setCallback(new FixedValue() {
     
            //FixedValue用来对所有拦截的方法返回相同的值 不会再调用代理目标类的相应方法
            @Override
            public Object loadObject() throws Exception {
     
                return "hello";
            }
        });
        SampleClass sampleClass =(SampleClass)enhancer.create();
        //test方法被拦截了  不执行  只打印了hello
        System.out.println(sampleClass.test());
        System.out.println(sampleClass.toString());
        System.out.println(sampleClass.getClass().getName());//没有被拦截,因为final
        //由于hashCode返回的是Number,而FixedValue返回的是String  所以报错
//        System.out.println(sampleClass.hashCode());
    }

    public static class SampleClass {
     
        public String test(){
     
            return "gLib";
        }
    }
}

运行结果:
2020-12-31_第4张图片

你可能感兴趣的:(动态代理,java)