拦截器(动态代理的升级)

之前一直在纠结拦截器中是怎么体现动态代理的,因为动态代理不难理解,而拦截器就是把代理工具类中的代码放到拦截器中实现,所以绑定方法和构造方法和普通的动态代理有一点点不同。

一、编写拦截器接口

package com.taylor.interceptor;

import java.lang.reflect.Method;

public interface Interceptor {
	/**
	 * 方法需要的4个参数
	 * 1.代理对象
	 * 2.真实对象
	 * 3.调用的方法
	 * 4.方法的参数
	 */	
	/*
	 * 1.before方法返回boolean值,它在真实对象调用之前执行,当返回值为true,则反射真实对象的方法,若返回值
	 * 为false,则调用around方法。
	 */
	public boolean before(Object object,Object target,Method method,Object[] args);
	
	public void after(Object object,Object target,Method method,Object[] args);

	public void around(Object object,Object target,Method method,Object[] args);
}


二、、编写拦截器接口实现类

package com.taylor.interceptor;

import java.lang.reflect.Method;

public class MyInterceptor implements Interceptor {

	@Override
	public boolean before(Object object, Object target, Method method, Object[] args) {
		System.out.println("反射方法前逻辑");
		return true;	//不反射被代理对象原有方法
	}

	@Override
	public void after(Object object, Object target, Method method, Object[] args) {
		System.out.println("反射方法后逻辑");
	}

	@Override
	public void around(Object object, Object target, Method method, Object[] args) {
		System.out.println("取代了被代理对象的方法");
	}

}

三、编写代理工具类

package com.taylor.interceptor;

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

public class InterceptorJdkProxy implements InvocationHandler{
	
	//把真实对象和拦截器传递进来
	private Object target;  //真实对象
	/*
	 * 这里传拦截器路径名的原因很简单,通过反射生成对象,而不是new
	 */
	private String InterceptorClass = null;	//这个是拦截器的路径名
	
	//通过构造方法把值传入
	public InterceptorJdkProxy(Object target, String interceptorClass) {
		this.target = target;
		InterceptorClass = interceptorClass;
	}
	
	
	//提供一个生成代理对象的方法,参数是真实对象和拦截器的全路径。
	public static Object bind(Object target, String interceptorClass) {
		
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
			target.getClass().getInterfaces(), 
			new InterceptorJdkProxy(target, interceptorClass));
		/*
		 *这里和动态代理不同的就是第三个参数,
		 *普通动态代理的第三个参数是this,表示当前对象,因为它调用的就是该类的方法。
		 *而这里的第三个参数是一个代理工具类的对象,因为它要调用的的方法是写在了拦截器中,
		 *刚好拦截器和真实对象又可以通过构造方法传递进来。
		 *至于为什么bind()写成static,是想通过类名直接调用,而无需生成多余对象。
		 */
		
	}
	
	
	/*
	 * proxy:代理对象
	 * method:被调用的方法
	 * args:方法所需参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//通过代理调用方法,首先进入这个方法
		if(InterceptorClass==null) {	//没传入拦截器,则直接反射原有方法
			return method.invoke(target, args);
		}
		Object result = null;	//返回值
		
		//通过反射生成拦截器
		Interceptor interceptor 
		= (Interceptor) Class.forName(InterceptorClass).newInstance();
		
		//调用前置方法
		if(interceptor.before(proxy, target, method, args)) {
			//反射原有方法
			result =  method.invoke(target, args);
		}else {
			//返回false执行取代方法
			interceptor.around(proxy, target, method, args);
		}
		interceptor.after(proxy, target, method, args);
		
		return result;
	}

	
	
}

四、编写被代理对象的接口和实现类

package com.taylor.dao;

public interface HelloWorld {
	public void say();
}


package com.taylor.dao;

public class HelloWorldImpl implements HelloWorld{

	@Override
	public void say() {
		System.out.println("hello world");
	}

}

五、测试类和运行结果

package com.taylor.test;

import com.taylor.dao.HelloWorld;
import com.taylor.dao.HelloWorldImpl;
import com.taylor.interceptor.InterceptorJdkProxy;

public class TestHelloWorld {
	public static void main(String[] args) {
		//1.代理对象
		HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),
				"com.taylor.interceptor.MyInterceptor");
		//2.通过代理对象调用方法
		proxy.say();
	}
}

*当before方法的返回值为true时,结果是

*当before方法的返回值为false时,结果是

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值