Java动态代理

1、java反射技术

//【java.lang.reflect.*】 反射专用包

// 反射:只要配置就能生成对象,解除程序耦合度,灵活,缺点是运行慢
ReflectServiceImple1 obj1 = (ReflectServiceImple1)Class.forName("com.alison.ssm.ReflectServiceImple1").newInstance();  //无参构造
ReflectServiceImple2 obj = (ReflectServiceImple2)Class.forName("com.alison.ssm.ReflectServiceImple2").getConstructor(String.class).newInstance("张三");    //有参构造
// Class.forName()就是给类加载器注册一个全限定名,并使用newInstance()实例化对象

// 反射方法
Method method = ReflectServiceImple1.class.getMethod("sayHello", String.class);        // 先获得Class对象,再使用getMethod方法 得到Method实例
Object retObj = method.invoke(new ReflectServiceImple1(), "alison");                    // 使用invoke激活方法,获得返回值,传入类实例和方法参数
// 也可以这样实现:
new ReflectServiceImple1().getClass().getMethod("sayHello", String.class)
// 【注意】一定用try..catch结构包裹,因为容易爆ClassNotFound或者IllegalAccess等的异常

2、动态代理

动态代理的意义在于生成一个占位,又称代理对象,来代理真实对象,从而控制真实对象访问

java中最常用的代理方式有 JDK, CGLIB, javassist, ASM等,常见前两种

主要有两个步骤:

1)代理对象与真实对象建立联系,生成代理对象

2)实现代理对象的代理逻辑方法

2.1 JDK动态代理

使用JDK动态代理,需要实现java.lang.reflect.InovationHandler接口,实现invoke 方法

// 真实操作类
public interface HelloWorld{
    public void sayHelloWorld();
}
public class HelloWorldImp implements HelloWorld{
    @override
    public void sayHelloWorld(){
        System.out.println("Hello World!");
    }
}

//【JDK动态代理】
// 需要实现java.lang.reflect.InvicationHandler接口,invoke()方法,且被代理类 必须有实现的接口!!  如 HelloWorldImp implements HelloWorld
public class JDKProxyExample implements InvicationHandler {
    private Object target;
    /**
    *    建立代理关系,返回代理对象
    *    @param     target 真实对象
    *    @return    代理对象    
    */
    public Object bind(Object target){
        this.target = target;
        // 三个参数:真实类加载器,接口数组,当前代理类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    /**
    *    代理逻辑方法:当使用代理对象调用某方法时,就会自动调用invoke方法
    *    @param     proxy 代理对象
    *    @param    method 当前调度方法
    *    @param    args 当前方法参数
    *    @return    代理结果返回
    *    @throws Trowable 异常
    */
    @override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑方法");
        System.out.println("在调用真实对象前的服务操作");
        Object obj = method.invoke(target, args);            // 反射启动·启用方法
        System.out.println("在调用真实对象后的服务操作");
        return obj;
    }
}

实现InvicationHandler 接口,主要有两个方法,bind用于和真实对象建立联系,返回代理对象,内部具体调用的是Proxy.newProxyInstance()方法,传入三个参数:类加载器,类接口(表示生成的动态代理对象挂在哪些接口下),当前类对象(必须实现invoke方法)

invoke方法就是可以启动被代理对象的真实方法了,可以加入自己的逻辑,使用的就是方法反射;当使用代理对象调用某方法时,就会自动调用invoke方法

测试:

    public void testJDKProxy(){
        JDKProxyExample jdk = new JDKProxyExample();
        HelloWorld proxy = (HelloWorld)jdk.bind(new HelloWorldImp());  // 此处需要强转下
        proxy.sayHelloWorld();    // 代理对象调用方法,会进入到代理类的invoke()方法中处理该方法
    }

 输出:

进入代理逻辑方法
在调用真实对象前的服务操作
Hello World!
在调用真实对象后的服务操作

 

 2.2 CGLIB动态代理

JDK代理必须提供接口,针对无接口实现的类,可以使用CGLIB

//【CGLIB动态代理】
// 优势:不要求被代理类 必须实现某接口
public class CglibProxyExample implements MethodInterceptor {
    /**
    *    生成CGLIB代理对象
    *    @param    cls ——Class类
    *    @return    Class类的CGLIB代理对象
    */
    public void getProxy(Class cls){
        //CGLIB enhancer增强类对象
        Enhancer enhancer = new Enhancer();
        // 设置增强类型
        enhancer.setSuperclass(cls);
        // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInteceptor犯法
        enhancer.setCallback(this);
        // 生成并返回代理对象
        return enhancer.create();
    }
    /**
    *    代理逻辑方法
    *    @param    methodProxy 方法代理
    *    ..
    */
    @override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.err.println("在调用真实对象前的服务操作");
        //CGLIB反射调用真实对象方法
        Object result = methodProxy.invokeSuper(proxy, args);
        System.err.println("在调用真实对象hou的服务操作");
        return result;
    }

    public void testCglibProxy(){
        CglibProxyExample cpe = new CglibProxyExample();
        ReflectServiceImple1 obj = (ReflectServiceImple1)cpe.getProxy(ReflectServiceImple1.class);
        obj.sayHello("张三");
    }
}

 本质上是调用了 Enhancer 类,基于父类进行生成代理对象

 

posted @ 2019-06-26 20:11  长亭古道随风  阅读(154)  评论(0编辑  收藏  举报