1 前言

Java动态代理机制使用十分广泛,如AOP的实现、Mybatis框架的实现,Java动态代理实现有两种方式:JDK动态代理和Cglib动态代理,下面就举例说明该如何使用。

2 JDK动态代理

2.1 实现说明

JDK动态代理生成代理对象,不需要借助第三方Jar,利用jar反射实现,目标对象必须实现接口

2.2 创建接口和实现类

接口如下:

package com.pengmm.service;

public interface UserService {
    public String getUserName(String name);
    public int getUserAge(int age);
}

接口实现类如下:

package com.pengmm.service;

public class UserServiceImpl implements UserService {

    @Override
    public String getUserName(String name) {
        System.out.println("name="+name);
        return name;
    }

    @Override
    public int getUserAge(int age) {
        System.out.println("age="+age);
        return age;
    }

}

2.3 实现InvocationHandler接口并生成代理对象

具体代码如下:

package com.pengmm.util;

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

/**
 * JDK动态代理生成代理对象,不需要借助第三方Jar,利用jar反射实现
 * 目标对象必须实现接口
 * @author pengmm
 */
public class JdkProxy implements InvocationHandler {
    // 目标对象
    private Object target;
    /**
     * 构造函数
     * @param target 目标对象
     */
    public JdkProxy(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置方法
        System.out.println(proxy.getClass().getName()+"==========代理的前置方法===============");
        Object result = method.invoke(target, args);
        System.out.println(target.getClass().getName()+"==========代理的后置方法===============");
        return result;
    }
    /**
     * 生成代理对象
     * @return
     */
    public Object getProxy() {
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        Object newProxyInstance = 
                Proxy.newProxyInstance(classLoader, interfaces, this);
        return newProxyInstance;
    }

}

2.4 测试调用

具体测试代码如下:

package test.com.pengmm.mapper;

import com.pengmm.service.UserService;
import com.pengmm.service.UserServiceImpl;
import com.pengmm.util.JdkProxy;

public class JdkTest {
    public static void main(String[] args) {
        // 创建目标对象
        UserService userService = new UserServiceImpl();
        // 生成并获取代理对象
        JdkProxy jdkProxy = new JdkProxy(userService);
        UserService proxy = (UserService) jdkProxy.getProxy();
        // 代理对象调用方法
        proxy.getUserName("张三");
        proxy.getUserAge(18);
    }
}

控制台结果如下:

com.sun.proxy.$Proxy0==========代理的前置方法===============
name=张三
com.pengmm.service.UserServiceImpl==========代理的后置方法===============
com.sun.proxy.$Proxy0==========代理的前置方法===============
age=18
com.pengmm.service.UserServiceImpl==========代理的后置方法===============

3 Cglib动态代理

3.1 说明

通过Cglib方式生成代理类,依赖jar包:asm-5.1.jar、cglib-3.2.4.jar,原理:根据目标类的字节码文件生成子类并拦截目标类的所有可继承方法,从而动态代理;
优势:可以代理具体类,不需要实现接口

3.2 创建并生成代理类

具体代码如下:

package com.pengmm.util;

import java.lang.reflect.Method;

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

/**
 * 通过Cglib方式生成代理类,依赖jar包:asm-5.1.jar、cglib-3.2.4.jar
 * 原理:根据目标类的字节码文件生成子类并拦截目标类的所有可继承方法,从而动态代理
 * 优势:可以代理具体类,不需要实现接口
 * @author pengmm
 *
 */
public class CglibProxy implements MethodInterceptor {
    // 增强类,用于创建子类,即代理类
    private Enhancer enhancer;  
    /**
     * 构造函数
     * @param target 目标类的Class对象,即字节码
     */
    public CglibProxy(Object target) {
        this.enhancer = new Enhancer();  
        enhancer.setSuperclass((Class<?>)target);  
        enhancer.setCallback(this); 
    }
    /**
     * 对目标类的可继承方法进行拦截
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("==========代理的前置方法===============");
        // 调用目标对象的方法
        Object result = methodProxy.invokeSuper(o, args);
        System.out.println("==========代理的后置方法===============");

        return result;
    }
    /**
     * 生成的代理对象
     * @return
     */
    public Object getProxy() {
        Object proxy = enhancer.create();  
        return proxy;
    }

}

3.3 测试调用

具体代码如下:

package test.com.pengmm.mapper;

import com.pengmm.service.UserServiceImpl;
import com.pengmm.util.CglibProxy;

public class CglibTest {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy(UserServiceImpl.class);  
        UserServiceImpl proxy = (UserServiceImpl) cglibProxy.getProxy();
        proxy.getUserName("张三");
        proxy.getUserAge(18);
    }
}

控制台输出结果如下:

==========代理的前置方法===============
name=张三
==========代理的后置方法===============
==========代理的前置方法===============
age=18
==========代理的后置方法===============