Java动态代理

一、JDK动态代理

jdk动态代理本质上是使用被代理对象的类加载器,通过被代理类实现的接口在运行时动态构造出代理类来增强原始类的功能的方法,需要使用Java的反射机制,通过实现InvocationHandler接口实现JDK动态代理。

1、先定义一个接口

package com.teriste.fanshe;

public interface HelloWorld {
    void sayHello(String name);
}

2、定义被代理类,该类实现了接口

package com.teriste.fanshe;

public class HelloWorldImpl implements HelloWorld {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello "+name);
    }
}

3、定义代理类,实现InvocationHandler接口

package com.teriste.fanshe;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK动态代理
 * 代理类必须实现了接口
 */
public class JdkProxyHandler implements InvocationHandler {

    //被代理的真实对象
    private Object target = null;

    /**
     * 建立代理对象和真实对象的代理关系,并返回代理对象
     * @param target 真实对象
     * @return 代理对象
     */
    public Object bind(Object target){
        this.target = target;
        //真实对象的类加载器 真实对象实现的接口 实现方法逻辑的代理类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /**
     * 代理方法逻辑
     * @param proxy 代理对象
     * @param method 真实对象被调用的方法
     * @param args 方法入参
     * @return 代理结果返回
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑方法");
        System.out.println("在调度真实对象前的服务");
        Object object = method.invoke(target,args);
        System.out.println("在调度真实对象后的服务");
        return object;
    }

    public static void main(String[] args) {
        JdkProxyHandler jdkProxyHandler = new JdkProxyHandler();
        //通过真实对象和代理对象绑定,返回一个代理对象,这个对象和真实对象实现了相同的接口
        HelloWorld helloWorld = (HelloWorld) jdkProxyHandler.bind(new HelloWorldImpl());
        //该接口调用的方法就是代理对象的invoke方法
        helloWorld.sayHello("张三");
    }
}

二、CGLIB动态代理

CGLIB动态代理是通过生成被代理类的子类来增强被代理类功能的方法,因此被代理类必须可以继承。

1、创建被代理类

package com.teriste.fanshe;

import java.lang.reflect.Method;

public class ReflectServiceImpl {

    public void sayHello(String name){
        System.out.println("Hello "+name);
    }

    public static void main(String[] args) {
        ReflectServiceImpl target = null;

        try {
            target = (ReflectServiceImpl)Class.forName("com.teriste.fanshe.ReflectServiceImpl").newInstance();
            Method method = target.getClass().getMethod("sayHello",String.class);
            method.invoke(target,"张三");
        }catch (NoSuchMethodException | ClassNotFoundException e){
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

2、创建代理类,实现MethodInterceptor接口

package com.teriste.fanshe;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * cglib动态代理
 * 代理类必须可以继承
 * 无法代理静态方法,需要使用asm修改字节码的静态代理方式
 */
public class CglibProxy implements MethodInterceptor{

    /**
     * 生成CGLIB动态代理对象
     * @param cls 被代理类的CLASS类
     * @return 类的CGLIB代理对象
     */
    public Object getProxy(Class cls){
        //CGLIB enhancer 增强类对象
        Enhancer enhancer = new Enhancer();
        //设置增强类型
        enhancer.setSuperclass(cls);
        //定义代理逻辑对象为当前对象,当前对象必须实现MethodInterceptor.intercept方法
        enhancer.setCallback(this);
        //生成并返回代理对象
        return enhancer.create();
    }

    /**
     * 代理逻辑方法
     * @param o 代理对象
     * @param method 被代理类的方法
     * @param objects 方法入参
     * @param methodProxy 方法代理
     * @return 代理逻辑返回
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用真实对象前");
        methodProxy.invokeSuper(o,objects);
        System.out.println("调用真实对象后");
        return null;
    }

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        ReflectServiceImpl reflectService = (ReflectServiceImpl) cglibProxy.getProxy(ReflectServiceImpl.class);
        reflectService.sayHello("张三");
    }
}

三、代理类的静态方法

cglib虽然可以代理类的方法,但是对于类的静态方法却无效,针对静态方法需要使用asm重写类的字节码来实现代理效果。

你可能感兴趣的:(Java)