前端初步入门spring-------07-代理衍生的拦截器

利用,代理的特性,我们可以制作一个拦截器,用来发出目标对象执行的通知

1、编写接口

一个五个通知,分别在业务执行的生命周期里:

  • before:前置通知,业务开始执行时发出
  • around:环绕通知,业务正在执行时发出,业务就在这个通知里面执行
  • afterReturning:后置通知,业务执行结束时发出
  • afterThrowing:异常通知,业务执行异常时发出
  • after:最终通知,业务不管执行与否,都会被调用
/**
 * 拦截器标准
 * 代理方法的 生命周期
 * @author PigIsDuc
 *
 */
public interface Interceptor {
	
	/**
	 * 
	 * 前置通知
	 * 
	 * 方法执行之前
	 * 如果返回为真true,那么后面的逻辑继续
	 * 返回为假false, 则方法不会执行
	 * 
	 * @param target 目标对象
	 * @param proxy  代理对象
	 * @param method 目标对象的每一个方法
	 * @param args   执行方法的参数
	 * @return
	 */
	boolean before(Object target, Object proxy, Method method, Object[] args);
	
	
	/**
	 * 
	 * 环绕通知
	 * 
	 * 方法在执行的时候
	 * 会得到方法执行的结果
	 * 方法如果真的执行了,只能在环绕通知里面执行
	 * 
	 * @param target 目标对象
	 * @param proxy  代理对象
	 * @param method 目标对象的每一个方法
	 * @param args   执行方法的参数
	 * @return
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	Object around(Object target, Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
	
	
	/**
	 * 后置通知
	 * 
	 * 方法执行之后,在执行这个节点的时候,方法已经有返回值了,所以可以接收返回值的结果
	 * 
	 * @param result 方法执行的结果
	 * @param proxy  代理对象
	 * @param method 目标对象的每一个方法
	 * @param args   执行方法的参数
	 */
	void afterReturning(Object result, Object proxy, Method method, Object[] args);
	
	
	/**
	 * 
	 * 异常通知
	 * 
	 * 方法抛出异常之后
	 * 
	 * @param e		 方法所抛出的异常
	 * @param proxy  代理对象
	 * @param method 目标对象的每一个方法
	 * @param args   执行方法的参数
	 */
	void afterThrowing(Exception e, Object proxy, Method method, Object[] args);
	
	/**
	 * 
	 * 最终通知
	 * 
	 * 最终,方法不管执行与否,都会被调用
	 * 
	 * @param target 目标对象
	 * @param proxy  代理对象
	 * @param method 目标对象的每一个方法
	 * @param args   执行方法的参数
	 */
	void after(Object target, Object proxy, Method method, Object[] args);
}

2、编写真正的拦截器

/**
 * 拦截器的实现类
 * @author PigIsDuck
 *
 */
public class InterceptorImpl implements Interceptor {

	public boolean before(Object target, Object proxy, Method method, Object[] args) {
		System.out.println("before InterceptorImpl");
		return true;
	}

	public Object around(Object target, Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		System.out.println("around InterceptorImpl");
        
        // 执行,获得方法返回值
		Object result = method.invoke(target, args);
		return result;
	}

	public void afterReturning(Object result, Object proxy, Method method, Object[] args) {
		System.out.println(" InterceptorImpl 后置");
	}

	public void afterThrowing(Exception e, Object proxy, Method method, Object[] args) {
		System.out.println(" InterceptorImpl 异常");
		e.printStackTrace();

	}

	public void after(Object target, Object proxy, Method method, Object[] args) {
		System.out.println(" InterceptorImpl after");
	}

}

3、改写代理对象的业务类,使其变成拦截器

public class ProxyProcessor implements InvocationHandler{
	
	// 目标对象 / 代理对象
	private Object target;
	// 使用拦截器增强目标对象
	private String interceptorName;
	
	public ProxyProcessor() {
	}

	public ProxyProcessor(Object target,  String interceptorName) {
		this.target = target;
		this.interceptorName = interceptorName; // 拦截器名称
	}

	/**
	 * 对代理对象中的所有方法的曾强逻辑
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		Object result = null;
		// 如果不启用拦截器
		if(this.interceptorName == null) {
			System.out.println("代理对象使用方法前");

			result = method.invoke(target, args);
			
			
			System.out.println("在" + new Date() + "\n使用了什么参数:" + Arrays.toString(args) + "\n调用了什么方法:" + method.getName());
			
			System.out.println("代理对象使用方法后");
		
		}else {
			// 利用反射,启用了拦截器
			Interceptor interceptor = (Interceptor) Class.forName(interceptorName).newInstance();
			try {
				if(interceptor.before(target, proxy, method, args)) {
					// 拦截器没有拦截出错误
					result = interceptor.around(target, proxy, method, args);
					interceptor.afterReturning(result, proxy, method, args);
				}else {
					// 拦截器拦截出错误
					throw new RuntimeException("前置通知未通过,方法终止");
				}
			} catch (Exception e) {
				interceptor.afterThrowing(e, proxy, method, args);
			}finally {
				interceptor.after(target, proxy, method, args);
			}
		}
		
		
		return result;
	}

}

4、使用拦截器

由于拦截器是使用代理编写的,所以,使用方式和代理的一样,只需要加入拦截器的地址就好

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userServiceImpl");
UserService userService2 = (UserService) ProxyFactory.bind(userService, "net.duck.spring.aop.reflect.InterceptorImpl");
System.out.println("users:" + userService2.queryAllUser());

结果:

init MockServlet1
before InterceptorImpl  // 开始
around InterceptorImpl  // 执行
net.duck.spring.ioc.dao.UserDao@5d11346a // 业务
 InterceptorImpl 后置    // 后置
 InterceptorImpl after  // 最终
users:[User [username=duck, password=123456], User [username=pig, password=1asd56]]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值