Java动态代理

Java动态代理简介

1.1 动态代理的特点

  字节码随用随创建,随用随加载。 

  它与静态代理的区别也在于此。

  因为静态代理是字节码一上来就创建好,并完成加载。

    装饰者模式就是静态代理的一种体现。

1.2 动态代理常用的有两种方式  

  1.基于接口的动态代理

    提供者:JDK官方的Proxy类

    要求:被代理类至少实现一个接口

  2.基于子类的动态代理

    提供者:第三方的CGLib ,如果报 asmxxx的异常,需要导入asm.jar

    要求:被代理类不能是被final修饰的类(即最终类)

需求:

   假设一个盖房子的工程(bulid a house)需要找工人到工地干活,要求工人会搬砖(move brick),砌墙(build a wall)。

一个包工头承接了这项工程,由包工头去找工人干活。此时的包工头即是代理的角色(proxyBulidAHouse)。

  使用动态代理对方法进行增强。

2  基于接口的动态代理—Proxy类

2.1新建盖房子的接口(IBulidHouse)

/**
* 建房子的要求
* 1.搬砖 moveBrick
* 2.砌墙 bulidWall
* 需要给工人工钱
* 工钱 money
*
*/
public interface IBuildHouse {
/**
* 搬砖的方法
* @param money 搬砖的工钱
*/
public void moveBrick(Float money);

/**
* 砌墙的方法
* @param money 砌墙的工钱
*/
public void buildWall(Float money);
}

2.2 接口实现类


/**
* 一个工人
* 实现接口表示这个工人符合会搬砖和会砌墙的要求
*/
public class BuildHouseImpl implements IBuildHouse{

public void moveBrick(Float money) {
System.out.println("今天搬砖得了"+money+"元");
}

public void buildWall(Float money) {
System.out.println("今天砌墙得了"+money+"元");
}
}

2.3代理类对象,对被代理对象的方法进行增强

public class ProxyBuildHouse {

    public static void main(String[] args) {

final IBuildHouse buildHouse = new BuildHouseImpl(); //直接new 一个被代理对象

/**
* 代理:
* 间接。
* 获取代理对象:
* 要求:
* 被代理类最少实现一个接口
* 创建的方式
* Proxy.newProxyInstance(三个参数)
* 参数含义:
* ClassLoader:和被代理对象使用相同的类加载器。
* Interfaces:和被代理对象具有相同的行为。实现相同的接口。
* InvocationHandler:
* 如何代理。
* 策略模式:使用场景是:
* 数据有了,目的明确。
* 如何达成目标,就是策略。
*/

IBuildHouse proxyBuildHouse = (IBuildHouse) Proxy.newProxyInstance(
buildHouse.getClass().getClassLoader(),
buildHouse.getClass().getInterfaces(),
new InvocationHandler() {

/**
* 执行被代理对象的任何方法,都会经过该方法。
* 此方法有拦截的功能。
*
* 参数:
* proxy:代理对象的引用。不一定每次都用得到
* method:当前执行的方法对象
* args:执行方法所需的参数
*返回值:
* 当前执行方法的返回值
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

String name = method.getName();
Float money = (Float) args[0];

Object reValue = null;

if("moveBrick".equals(name)){
/**
* 对砌墙方法进行增强,如果工钱大于500
* 包工头收百分二十工钱,工人实际到手工钱的百分之八十
*/
if(money>500){
reValue=method.invoke(buildHouse,money*0.8f);
}
}

if("buildWall".equals(name)){
/**
* 对砌墙方法进行增强,如果工钱大于500
* 包工头收百分二十工钱,工人实际到手工钱的百分之八十
*/
if(money>500){
reValue=method.invoke(new BuildHouseImpl(),money*0.8f);
}
}
return reValue;
}
}
);

//直接调用搬砖和砌墙方法
//buildHouse.moveBrick(700f);
//buildHouse.buildWall(600f);


//代理对象执行搬砖和砌墙的方法
proxyBuildHouse.moveBrick(600f);
proxyBuildHouse.buildWall(700f);

}
}

3  基于子类的动态代理—CGLib.Enhaner类

3.1 新建BuildHouseImpl类(没有实现接口)

/**
* 一个工人
* 没有实现接口
*/
public class BuildHouseImpl {

public void moveBrick(Float money) {
System.out.println("今天搬砖得了"+money+"元");
}

public void buildWall(Float money) {
System.out.println("今天砌墙得了"+money+"元");
}
}

3.2 新建CglibBuildHouse代理类(没有实现接口)

public class CglibBuildHouse {
public static void main(String[] args) {

final BuildHouseImpl buildHouse = new BuildHouseImpl();

/**
* 动态代理:
* 特点:字节码随用随创建,随用随加载
* 作用:不修改源码的接触上对源码进行增强
* 分类:基于接口的动态代理
* 基于子类的动态代理
*基于子类的动态代理:
* 涉及的类:Enhancer
* 提供者:第三方cglib库
* 如何创建代理对象:
* 使用Enhancer类的create方法
* 创建代理对象的要求:
* 被代理类不能是最终类
* create方法的参数:
* Class:字节码
* 作用:用于指定被代理对象的字节码
*
* Callback:用于提供增强的代码
* 它是让我们写如何代理,一般写一个该接口的实现类,通常情况下写一个匿名内部类,但不是必须的。
* 此接口的实现类都是谁用谁写
* 一般写该接口的子类的实现类:MethodInterceptor
*
*/
BuildHouseImpl cgLibBuildHouse = (BuildHouseImpl) Enhancer.create(buildHouse.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的任何方法都会经过该方法
* @param proxy
* @param method
* @param objects
* 以上三个参数和基于接口动态代理中invoke方法的参数是一样的
* @param methodProxy 当前执行方法的代理对象
* @return
* @throws Throwable
*/
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//获取被代理类方法名
String name=method.getName();
//获取方法所需参数
Float money = (Float) objects[0];
Object returnValue = null;

if("moveBrick".equals(name)){
/**
* 对砌墙方法进行增强,如果工钱大于500
* 包工头收百分二十工钱,工人实际到手工钱的百分之八十
*/
if(money>500){
returnValue=method.invoke(buildHouse,money*0.8f);
}
}
if("buildWall".equals(name)){
/**
* 对砌墙方法进行增强,如果工钱大于500
* 包工头收百分二十工钱,工人实际到手工钱的百分之八十
*/
if(money>500){
returnValue=method.invoke(buildHouse,money*0.8f);
}
}

return returnValue;
}
});

cgLibBuildHouse.buildWall(600f);
cgLibBuildHouse.moveBrick(600f);
}
}
原文地址:https://www.cnblogs.com/lifengSkt/p/12907451.html