Java Web实战06--Spring之AOP使用

一、AOP简介

Spring AOP是面向切面编程,主要思想是,将代码中的与主业务逻辑无关的公共代码,抽离出来,单独模块化为类即切面,在运行的时候动态的将切面的功能即通知加入到业务执行逻辑中。AOP模块常用于日志处理、事务管理、权限验证、参数验证等。优点:

–每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
–业务模块更简洁, 只包含核心业务代码.

以下是Aop中的主要概念:

•切面(Aspect):  横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
•通知(Advice):  切面必须要完成的工作
•目标(Target):被通知的对象
•代理(Proxy): 向目标对象应用通知之后创建的对象
•连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。
切点(pointcut):每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。

AOP的实现原理为代理模式,一个用代理实现的代码如下:

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

public class ArithmeticCalculatorLoggingProxy {
	
	private ArithmeticCalculator target;
	public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
		super();
		this.target = target;
	}
	//返回代理对象
	public ArithmeticCalculator getLoggingProxy(){
		ArithmeticCalculator proxy = null;
		
		ClassLoader loader = target.getClass().getClassLoader();
		Class [] interfaces = new Class[]{ArithmeticCalculator.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("[before] The method " + methodName + " begins with " + Arrays.asList(args));				
				//调用目标方法
				Object result = null;				
				try {
					//前置通知
					result = method.invoke(target, args);
					//返回通知, 可以访问到方法的返回值
				} catch (NullPointerException e) {
					e.printStackTrace();
					//异常通知, 可以访问到方法出现的异常
				}				
				//后置通知. 因为方法可以能会出异常, 所以访问不到方法的返回值			
				//打印日志
				System.out.println("[after] The method ends with " + result);
				return result;
			}
		};
		
		/**
		 * loader: 代理对象使用的类加载器。 
		 * interfaces: 指定代理对象的类型. 即代理代理对象中可以有哪些方法. 
		 * h: 当具体调用代理对象的方法时, 应该如何进行响应, 实际上就是调用 InvocationHandler 的 invoke 方法
		 */
		proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
		
		return proxy;
	}
}
在使用的时候需要将原始的类传递到此代理类,然后用代理类来实现对业务类的所有操作,在实际使用时是比较麻烦的。

二、Spring AOP实战

1、建立一个maven工程,在pom.xml中加入以下依赖,其中,aspectjweaver、aopalliance是用来支持aop注解aspect和Before的。


		
			junit
			junit
			3.8.1
			test
		
		
		
			org.springframework
			spring-context
			4.3.0.RELEASE
		
		
		
			org.springframework
			spring-core
			4.3.0.RELEASE
		
		
		
			org.springframework
			spring-beans
			4.3.0.RELEASE
		
		
		
			org.springframework
			spring-expression
			4.3.0.RELEASE
		

		
		
			org.springframework
			spring-aop
			4.3.0.RELEASE
		

		
		
			aopalliance
			aopalliance
			1.0
		 

		
		
			org.aspectj
			aspectjweaver
			1.8.9
		

	


2、实现一个接口move以及实现类,表示向某个方向移动:

package com.yefeng.spring.spring4;

public interface Move {
	public void up(int i);
	public void down(int i);
	public void left(int i);
	public void right(int i);
}

package com.yefeng.spring.spring4;

import org.springframework.stereotype.Component;

@Component
public class MyMove implements Move {

	@Override
	public void up(int i) {
		System.out.println("I'm moving up " + i + " steps!");
	}

	@Override
	public void down(int i) {
		System.out.println("I'm moving down " + i + " steps!");
	}

	@Override
	public void left(int i) {
		System.out.println("I'm moving left " + i + " steps!");
	}

	@Override
	public void right(int i) {
		System.out.println("I'm moving right " + i + " steps!");
	}

}


3、编写打印日志类,注意此处在before注解后,需要加入通知的方法,并且括号中的参数一定要和方法的参数一致。例如下中,括号中int不能省略。可以用*表示所有含有一个int参数的方法。

package com.yefeng.spring.spring4;

import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingMove {
	//下面的()中int 不能省略
	//@Before("execution(public void com.yefeng.spring.spring4.Move.up(int))")
	//此处中类名为接口或者实现类都可以
//	@Before("execution(public void com.yefeng.spring.spring4.MyMove.up(int))")
	@Before("execution(public void com.yefeng.spring.spring4.MyMove.*(int))")
	public void beforeMove(JoinPoint joinPoint){
		String name = joinPoint.getSignature().getName();
		List args = Arrays.asList(joinPoint.getArgs());
		System.out.println("I'm ready to move " + name +" " + args);
	}
}


4、在spring bean配置文件中加入自动扫面bean以及aop动态代理支持,注意需要加入命名空间context,aop:










5、测试app类:

package com.yefeng.spring.spring4;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author yefengzhichen
 * 2016年7月5日
 */
public class App 
{
    public static void main( String[] args )
    {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationConetsx.xml");
        Move move = (Move) ctx.getBean("myMove");
        move.up(3);      
        move.down(2);
    }
}


6、执行结果:

I'm ready to move up [3]
I'm moving up 3 steps!
I'm ready to move down [2]
I'm moving down 2 steps!











你可能感兴趣的:(JAVAWEB,spring,java,web,JAVA,AOP)