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;
}
}