JavaCore-DynamicProxy

在运行时动态对某些东西代理,代理它做了其他事情。

public interface Developer{
	void code();
	void debug();
}
public class JavaDeveloper implements Developer{
	private String name;
	JavaDeveloper(String name){
		this.name = name;
	}
	
	@Override
	public void code(){
		System.out.println(this.name+"is coding java");
	}
	
	@Override
	public void debug(){
		System.out.println(this.name+"is debugging java");
	}
} 

但是有一个叫Zack的程序员他在开发时候,通常没有bug,这是他后天养成的,我们应该在这个程序员的成长期去实现这个特性,而不是在他出生之前就定义。

public class JavaDynamicProxy{
	public static void main(String[] args){
		JavaDeveloper zack= new JavaDeveloper("Zack");

		Developer zackProxy=(Developer) Proxy.newProxyInstance(zack.getClass().getClassLoader(),
							zack.getClass().getInterfaces(),(proxy,method,agrs)->{
								if(method.getName().equals("code")){
									System.out.println("Zack is praying for the code!");
									return method.invoke(zack,agrs);
									}
								if(method.getName().equals("debug")){
									System.out.println("Zack's have no bug! No need to debug!");
									return null;
								}
								return null;
									});
		zackProxy.code();
		zackProxy.debug();
	}
}

代理后显示结果:

Zack is praying for the code!
Zack is coding java
Zack's have no bug!No need to debug!

分析
如何使用动态代理,生成一个实例对象,然后用Proxy的newInstance方法对这个实例对象代理生成一个代理对象。
在这里插入图片描述
zackProxy的类型是Developer接口,而不是一个实现类,因为Zack在被代理后生成的对象,并不属于Developer接口的任何一个实现类。但是他是基于Developer接口和Zack类加载代理出来的。

public static Object newProxyInstance(ClassLoaderloader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
// load the  class loader to define the proxy class
// interfaces the list of interfaces for the proxy class to implement
// the invocation handler to dispatch method invocations to

loader,选用的类加载器,因为代理的是zack,所以一般都会用加载zack的类加载器
interfaces,被代理类所实现的接口,这个接口可以使多个
h,绑定代理类的一个方法。

简而言之:loader和interfaces基本决定了这个类到底是个怎么样的类。而h是invocationHandler,决定了这个代理类到底是多了什么功能。所以动态代理的内容重点就是这个invocationHandler,InvocationHandler作用就是,当代理对象的原本方法被调用时候,会绑定执行一个方法,这个方法就是Invocationhandler里面定义的内容,同时会替代原本方法的结果返回。

InvocationHandler接收三个参数:
proxy 代理后的实例对象
method 对象呗调用方法
args 调用时的参数

使用场景:
可以在运行的时候才切入改变类的方法,而不需要预先定义它。
动态代理一般很少去手写,但用的其实很多,在Spring项目中用的注解,例如历来注入的@Bean,@Autowired 事务注解@Transactional等都有用到,换言之就是Spring的AOP(切面编程)

动态代理第二种实现-CGlib
cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。
因为采用的是继承,所以不能对final修饰的类进行代理

1 首先定义业务类,无需实现接口(也可以实现接口,无所谓)
public class BookFacadeImpl1{
	public void addBook(){
		System.out.println("新增图书...");
	}
}

2 实现MehodInterceptor方法代理接口,创建代理类

public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;//业务类对象,供代理方法中进行真正的业务方法调用
  
    //相当于JDK动态代理中的绑定
    public Object getInstance(Object target) {  //返回动态代理对象
        this.target = target;  //给业务对象赋值
        Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类
        enhancer.setSuperclass(this.target.getClass());  //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this); 
       // 创建动态代理类对象并返回  
       return enhancer.create(); 
    }
    // 实现回调方法 
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
        System.out.println("预处理——————");
        proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
        System.out.println("调用后操作——————");
        return null; 
    }

3 创建业务类和代理类对象,然后通过代理类对象.getInstance(业务类对象)返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指定它)。最后通过动态代理类对象进行方法调用

public static void main(String[] args) {      
        BookFacadeImpl1 bookFacade=new BookFacadeImpl1();
        BookFacadeCglib  cglib=new BookFacadeCglib();  
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(bookFacade);  
        bookCglib.addBook();  
    }

比较:
JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法
CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值