適用於具備橫切邏輯的場合,如性能檢測、訪問控制、事務管理及日誌記。編程
Spring 近支持方法的鏈接點,能在方法調用前、方法調用後、方法拋出異常時及方法調用先後這些執行點織入加強bash
鏈接點是客觀存在的方法ide
指定在哪些類的哪些方法上織入橫切邏輯
一個切點能夠匹配多個鏈接點
對應鏈接點表達式性能
加強是織入目標類鏈接點上的橫切邏輯代碼,包含定位鏈接點的方位信息ui
切面由切點和加強組成。對應一個類this
織入是將加強添加到目標類的具體鏈接點上的過程。
Spring採用動態代理織入,AspectJ採用編譯器織入和類裝載期織入。spa
@Slf4j
@Aspect
@Component
public class LogAspect {
ThreadLocal<Long> startTime = new ThreadLocal<>();
@Pointcut("execution(public * com.pengtech.school.*.controller..*.*(..))")
public void logPointCut(){
}
@Before("logPointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到請求,記錄請求內容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
startTime.set(System.currentTimeMillis());
log.info("########請求地址:" + request.getRequestURL());
log.info("########開始時間:" + LocalDateTime.now());
log.info("########請求方法:" + joinPoint.getSignature().getDeclaringTypeName() +
"." + joinPoint.getSignature().getName());
Object[] args = joinPoint.getArgs();
for (Object param : args) {
log.info("########方法參數:" + param);
}
}
@After("logPointCut()")
public void doAfter() throws Throwable {
log.info("#######執行間隔:" + (System.currentTimeMillis() - startTime.get())
+ "ms");
log.info("#######完成時間:" + LocalDateTime.now());
}
}
複製代碼
適合具備橫切邏輯的應用場合,如性能監測、訪問控制、事務管理和日誌記錄。
Spring AOP使用動態代理技術在運行期向目標類織入加強的代碼。
複製代碼
在運行期建立接口的代理實例
限制:只能爲接口建立代理實例
// InvocationHandler 實現該接口定義橫切邏輯,並經過反射機制調用目標類的代碼,動態的將橫切邏輯和業務邏輯編織在一塊兒。
public class PerformanceHandler implements InvocationHandler {
// 目標業務類
private Object target;
public PerformanceHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 橫切代碼
PerformanceMonitor.begin(target.getClass().getName()+"."+ method.getName());
// 反射調用目標類的目標方法
Object object = method.invoke(target, args);
// 橫切代碼
PerformanceMonitor.end();
return object;
}
}
Proxy 利用InvocationHandler動態建立一個符合某一接口的實例,生成目標類的代理對象
// 使用JDK動態代理
// 被代理的目標業務類
ForumService target = new ForumServiceImpl();
// 將目標業務類和橫切代碼編織到一塊兒
PerformanceHandler handler = new PerformanceHandler(target);
// 建立代理實例
ForumService proxy = (ForumService) Proxy.newProxyInstance(target
.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
// 調用代理方法
proxy.removeForum(10);
proxy.removeTopic(1012);
複製代碼
動態建立子類的方式生成代理對象
不能對final或private方法進行代理
//實現MethodInterceptor接口,並重寫intercept方法
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
//建立動態代理對象
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
// 攔截全部目標類方法的調用
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());
Object result=proxy.invokeSuper(obj, args);
PerformanceMonitor.end();
return result;
}
//動態生成子類的方式建立代理類
CglibProxy cglibProxy = new CglibProxy();
ForumService forumService = (ForumService)cglibProxy.getProxy(ForumServiceImpl.class);
forumService.removeForum(10);
forumService.removeTopic(1023);
}
複製代碼