spring实战-基于注解的面向切面编程(AOP)

Spring提供了强大的面向切面编程,实现对象之间的解耦,目前Spring-aop仅提供基于函数的切面

TestMain

package com.halfworlders.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.halfworlders.service.Server;
import com.halfworlders.service.ServerConfig;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=ServerConfig.class)
public class TestMain7 {

	@Autowired(required=false)
	private Server server;
	
	@Test
	public void test(){
		String[] args = new String[3];
		args[0] = "www";
		args[1] = "halfworlders";
		args[2] = "com";
		System.out.println(server.service(args));
		System.out.println("--------------------");
		System.out.println(server.getUserInfo(123));
	}
}
Log

package com.halfworlders.log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 申明一个切面
 */
@Aspect
public class Log {

	/**
	 * 设置无参切入点
	 */
	@Pointcut("execution(** com.halfworlders.service.Server.service(..))")
	public void service(){
		
	}
	
	/**
	 * 设置有参切入点
	 * args(userId)中参数名称userId必须与切点方法签名中的参数相匹配
	 */
	@Pointcut(value="execution(* com.halfworlders.service.Server.getUserInfo(..)) && args(userId)")
	public void getUserInfo(int userId){
		
	}
	/**
	 * 通知方法在目标方法调用之前执行
	 * 带参aop,getUserInfo(userId)中的参数名userId与切点方法中的参数同名
	 */
	@Before("getUserInfo(userId)")
	public void before(int userId) {
		System.out.println("before getUserInfo userId:" + userId);
	}
	
	/**
	 * 通知方法将目标方法封装起来
	 * 该方法的入参是必须的,并且必须调用jp.proceed(),否则会阻塞目标方法的调用
	 * 该方法是最为强大的,可以通过该方法监控切点执行效率,打印日志,为切点添加事务等
	 * 另外还有一个点是,可以通过jp.proceed()的返回值,进行错误重试,多次调用
	 */
	@Around("service()")
	public Object around(ProceedingJoinPoint jp) {
		Object proceed = null;
		
		String[] args = (String[])jp.getArgs()[0];
		System.out.print("入参:");
		for (Object arg : args) {
			System.out.print("["+arg+"]");
		}
		System.out.println("");
		
		try {
			System.out.println("around-before");
			long startTime = System.currentTimeMillis();
			proceed = jp.proceed();
			long endTime = System.currentTimeMillis();
			System.out.println("runtime:"+(endTime-startTime)+"ms");
			System.out.println("around-after");
		} catch (Throwable e) {
			System.out.println("around-exception");
		} finally {
			
		}
		System.out.println("出参:" + proceed);
		return proceed;
	}
	
	/**
	 * 通知方法在目标方法返回后调用
	 */
	@AfterReturning("service()")
	public void afterReturning(){
		System.out.println("afterReturning");
	}
	
	/**
	 * 通知方法在目标方法抛出异常时调用
	 */
	@AfterThrowing("service()")
	public void afterThrowing(){
		System.out.println("afterThrowing");
	}
	
	/**
	 * 通知方法在目标方法返回或者抛出异常时调用
	 */
	@After("service()")
	public void after(){
		System.out.println("after");
	}
}
ServerConfig

package com.halfworlders.service;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import com.halfworlders.log.Log;

/**
 * @EnableAspectJAutoProxy 注解启动自动代理功能
 */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ServerConfig {
	
	@Bean
	public Log log() {
		return new Log();
	}
}
Server

package com.halfworlders.service;

import org.springframework.stereotype.Component;

@Component
public class Server {
	public String service(String[] params) {
		String retVal = "";
		for(String arg : params){
			retVal = retVal.concat(arg).concat(".");
		}
		return retVal.substring(0, retVal.length()-1);
	}
	
	public String getUserInfo(int userId) {
		return "user:"+userId;
	}
}





你可能感兴趣的:(spring)