spring--(15)AOP基础

需求:有一个接口,里面有多个方法,如今须要记录每一个方法的开始与结束。
//接口以下java

public interface Calculator {
	int add(int i,int j);
	int sub(int i,int j);
	
}

//接口实现以下程序员

public class CalculatorImpl implements Calculator{

	@Override
	public int add(int i, int j) {
		int result = i+j;
		return result;
	}

	@Override
	public int sub(int i, int j) {
		int result = i-j;
		return result;
	}

}

1.常规作法,在每一个方法的开始与结束的地方加上log。以下spring

public class CalculatorImpl implements Calculator{

	@Override
	public int add(int i, int j) {
		System.out.println("The method add begin["+i+","+j+"]");
		int result = i+j;
		System.out.println("The method add end"+result);
		return result;
	}

	@Override
	public int sub(int i, int j) {
		System.out.println("The method sub begin["+i+","+j+"]");
		int result = i-j;
		System.out.println("The method sub end"+result);
		return result;
	}

}

1.1 测试代码数据库

public class Main {
	public static void main(String[] args) {
		Calculator calculator = new CalculatorImpl();
		calculator.add(1, 2);
		calculator.sub(4, 2);	
	}
}

1.2 输出结果编程

The method add begin[1,2]
The method add end3
The method sub begin[4,2]
The method sub end2

2.很明显上述能够知足每一个方法执行先后输出log的要求,可是若是输出的内容稍微改一点,那么将是大面积的修改log,所以上述方法不是很适合大型项目的log需求。
2.1 采用动态代理方法实现,添加代理类框架

package com.test.aop;

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

public class CalculatorProxy {
	
	//要代理的对象
	private Calculator target;
	//返回代理对象
	public Calculator getProxy(){
		Calculator proxy = null;
		
		//代理对象由哪个类加载器负责加载
		ClassLoader loader = target.getClass().getClassLoader();
		//代理对象的类型,即其中有哪些方法
		Class [] interfaces = new Class[]{Calculator.class};
		//当调用代理对象的方法时,执行该代码
		InvocationHandler h = new InvocationHandler() {
			/**
			 * proxy:正在执行的代理对象,通常不使用该对象
			 * method:正在被调用的方法
			 * args:调用方法时传入的参数
			 */
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				String methodName = method.getName();
				//日志开始
				System.out.println("The method"+methodName+" begin "+Arrays.asList(args));
				//执行方法
				Object oj = method.invoke(target, args);
				//日志结束
				System.out.println("The method"+methodName+" end "+oj);
				return oj;
			}
		};
		proxy = (Calculator) Proxy.newProxyInstance(loader, interfaces, h);
		
		return proxy;
	}
	public CalculatorProxy(Calculator target) {
		this.target = target;
	}
}

2.2 main方法ide

public class Main {
	
	public static void main(String[] args) {
		
		Calculator target = new CalculatorImpl();
		Calculator proxy = new CalculatorProxy(target).getProxy();
		int result = proxy.add(1, 2);
		System.out.println(result);
		result = proxy.sub(4, 2);
		System.out.println(result);
	}
}

2.3输出测试

The methodadd begin [1, 2]
The methodadd end 3
3
The methodsub begin [4, 2]
The methodsub end 2
2

3.如上的方法彻底能够知足需求,可是不可能每一个程序员都懂动态代理,加之spring框架自己也提供了相应的解决方法,即AOP(面向切面编程)。举个简单的实例,一个业务逻辑由以下部分组成:
1>验证参数
2>前置日志
3>方法,即核心实现
4>后置日志
AOP经常使用术语:
1.切面:如上业务逻辑组成部分,每一个点都是一个切面。
2.通知:切面完成的功能。
3.目标:被通知的对象,即如上业务逻辑组成部分中的 方法。
4.代理:它是一个对象,它的做用是通知目标对象。
5.链接点:指的是程序的某个位置,例如:某个方法被调用以前、调用以后,或是抛出异常的位置。
6.切点:每一个类都拥有多个链接点,AOP经过切点定位到指定的链接点。例如:链接点至关于数据库中的记录(记录有多条),切点至关于查询条件,它能查询到某一条记录。开始调用切面的时候叫作切点,简单的理解为在哪里开始调用日志、事务的地方。this

相关文章
相关标签/搜索