日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
面試問(wèn)爛的SpringAOP,再搞不懂沒(méi)臉回家過(guò)年了……

AOP可以通過(guò)代理模式來(lái)實(shí)現(xiàn)。下面介紹幾種常見(jiàn)的代理模式

代理模式

靜態(tài)代理

靜態(tài)代理指的是在編譯期就對(duì)目標(biāo)對(duì)象的方法進(jìn)行增強(qiáng)。例如我們程序中有如下接口:

public class Order {

interface OrderService{
/**
* 購(gòu)買(mǎi)商品
* @param goods
*/
void payForGoods(String goods);
}

static class OrderServiceImpl implements OrderService{

@Override
public void payForGoods(String goods) {
System.out.println("下單 " + goods + " 商品成功!");
}
}

public static void main(String[] args) {
OrderService orderService = new OrderServiceImpl();
orderService.payForGoods("牛奶");
}

}


如果想在購(gòu)買(mǎi)商品時(shí)獲取當(dāng)前時(shí)間,可以通過(guò)靜態(tài)代理增添代理類(lèi)對(duì) payForGoods 方法進(jìn)行增強(qiáng):

public class Order {

interface OrderService{
/**
* 購(gòu)買(mǎi)商品
* @param goods
*/
void payForGoods(String goods);
}

static class OrderServiceImpl implements OrderService{

@Override
public void payForGoods(String goods) {
System.out.println("下單 " + goods + " 商品成功!");
}
}

static class OrderProxy implements OrderService {


private OrderService orderService;

public OrderProxy(OrderService orderService) {
this.orderService = orderService;
}

@Override
public void payForGoods(String goods) {
System.out.println("當(dāng)前時(shí)間:" + LocalDateTime.now());
orderService.payForGoods(goods);
}
}

public static void main(String[] args) {
OrderService orderProxy = new OrderProxy(new OrderServiceImpl());
orderProxy.payForGoods("牛奶");
}

}


JDK動(dòng)態(tài)代理

JDK動(dòng)態(tài)代理主要涉及到 java.lang.reflect 包中的兩個(gè)類(lèi) Proxy 和 InvocationHandler。

InvocationHandler 是一個(gè)接口,通過(guò)實(shí)現(xiàn)該接口定義橫切邏輯,并通過(guò) 反射機(jī)制 調(diào)用目標(biāo)類(lèi)的代碼,動(dòng)態(tài)將橫切邏輯和業(yè)務(wù)邏輯放在一起。

Proxy 利用 InvocationHandler 動(dòng)態(tài)創(chuàng)建一個(gè)符合某一接口的實(shí)例,生成目標(biāo)類(lèi)的代理對(duì)象。實(shí)現(xiàn)代碼如下:

public class Order {

interface OrderService{
/**
* 購(gòu)買(mǎi)商品
* @param goods
*/
void payForGoods(String goods);
}

static class OrderServiceImpl implements OrderService{

@Override
public void payForGoods(String goods) {
System.out.println("下單 " + goods + " 商品成功!");
}
}

public static void main(String[] args) {
OrderService orderService = new OrderServiceImpl();
OrderService orderProxy = (OrderService) Proxy.newProxyInstance(OrderServiceImpl.class.getClassLoader(),
OrderServiceImpl.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("當(dāng)前時(shí)間:" + LocalDateTime.now());
Object result = method.invoke(orderService, args);
return result;
}
});
orderProxy.payForGoods("牛奶");
}

}


CGLib動(dòng)態(tài)代理

CGLib 全稱(chēng)為 Code Generation Library,是一個(gè)強(qiáng)大的高性能的 代碼生成類(lèi)庫(kù),可以在運(yùn)行期間擴(kuò)展 Java 類(lèi)與實(shí)現(xiàn) Java 接口,CGLib 封裝了ASM,可以在運(yùn)行期間生成新的 class。

相對(duì)于 JDK動(dòng)態(tài)代理 中只能為實(shí)現(xiàn)了接口的目標(biāo)類(lèi)創(chuàng)建實(shí)例,CGLib對(duì)于沒(méi)有通過(guò)接口定義業(yè)務(wù)方法的類(lèi)也可以創(chuàng)建動(dòng)態(tài)代理。

public class Order {

static class OrderServiceImpl{

public void payForGoods(String goods) {
System.out.println("下單 " + goods + " 商品成功!");
}
}

public static void main(String[] args) {
OrderServiceImpl orderService = new OrderServiceImpl();
OrderServiceImpl orderProxy = (OrderServiceImpl) Enhancer.create(orderService.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("當(dāng)前時(shí)間:" + LocalDateTime.now());
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
});
orderProxy.payForGoods("牛奶");
}

}


上面三種代理方式對(duì)比如下:

Spring AOP

Spring中的AOP功能為我們提供更加簡(jiǎn)單便捷的代理實(shí)現(xiàn)方式:

@Aspect
@Component
public class OrderAspect {

@Before("execution(public com.project.springaop.test.Order.payForGoods(..))")
public void getLocalDateTimeBefore(){
System.out.println("當(dāng)前時(shí)間:" + LocalDateTime.now());
}

@After("execution(public com.project.springaop.test.Order.payForGoods(..))")
public void getLocalDateTimeAfter(){
System.out.println("當(dāng)前時(shí)間:" + LocalDateTime.now());
}
}


相關(guān)術(shù)語(yǔ)

源碼分析

Spring提供了 JDK 和 CGLib 兩種方式來(lái)生成代理對(duì)象,具體使用哪種方式生成由AopProxyFactory 根據(jù) AdvisedSupport 對(duì)象的配置來(lái)決定。

默認(rèn)的策略是,如果目標(biāo)類(lèi)實(shí)現(xiàn)了接口,則使用JDK動(dòng)態(tài)代理技術(shù),否則使用Cglib來(lái)生成代理。

在 Spring Bean的生命周期中,代理對(duì)象的創(chuàng)建發(fā)生在初始化方法initializeBean后期的后置處理器中。

即BeanPostProcessor.postProcessAfterInitialization 方法中。

相關(guān)源碼

Advice注解

@Before 前置通知

前置通知會(huì)在目標(biāo)方法執(zhí)行前執(zhí)行

@Before("execution(public com.project.springaop.test.Order.payForGoods(..))")
public void before(JoinPoint joinPoint){
System.out.println("執(zhí)行前置通知,目標(biāo)方法:" + joinPoint.getSignature().getName() + ",方法參數(shù):" + joinPoint.getArgs());
}


@After 后置通知

后置通知會(huì)在目標(biāo)方法執(zhí)行后執(zhí)行,此通知無(wú)論如何都會(huì)執(zhí)行,即使目標(biāo)方法執(zhí)行出現(xiàn)了異常。

@After("execution(public com.project.springaop.test.Order.payForGoods(..))")
public void after(JoinPoint joinPoint){
System.out.println("執(zhí)行后置通知,目標(biāo)方法:" + joinPoint.getSignature().getName() + ",方法參數(shù):" + joinPoint.getArgs());
}


@AfterReturning 返回通知

返回通知會(huì)在目標(biāo)方法成功執(zhí)行后執(zhí)行,如果目標(biāo)方法出現(xiàn)了異常,則該通知不執(zhí)行。

@AfterReturning(value = "execution(public com.project.springaop.test.Order.payForGoods(..))", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result){
System.out.println("執(zhí)行返回通知,目標(biāo)方法:" + joinPoint.getSignature().getName() + ",方法參數(shù):" + joinPoint.getArgs() + ",執(zhí)行結(jié)果" + result);
}


@AfterThrowing 異常通知

異常通知會(huì)在目標(biāo)方法出現(xiàn)異常后執(zhí)行,如果目標(biāo)方法未出現(xiàn)異常則不執(zhí)行。

@AfterThrowing(value = "execution(public com.project.springaop.test.Order.payForGoods(..))", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Exception e){
System.out.println("執(zhí)行異常通知,目標(biāo)方法:" + joinPoint.getSignature().getName() + ",方法參數(shù):" + joinPoint.getArgs() + ",執(zhí)行異常" + e);
}


@Around 環(huán)繞通知

包圍一個(gè)連接點(diǎn)的通知,可以完成其他四種通知的所有功能。

@Around(value = "execution(public com.project.springaop.test.Order.payForGoods(..))")
public Object around(ProceedingJoinPoint joinPoint, Exception e){
Object result = null;
try{
System.out.println("執(zhí)行前置通知");
result = joinPoint.proceed();
System.out.println("執(zhí)行返回通知");
} catch (Throwable throwable) {
System.out.println("執(zhí)行異常通知");
} finally {
System.out.println("執(zhí)行后置通知");
}
return result;
}


一個(gè)方法被 Aspect類(lèi)攔截時(shí),執(zhí)行順序如下:

@Around > @Before > 原方法 > @Around > @After > @AfterReturing / @AfterThrowing

多個(gè) Aspect 的執(zhí)行順序可以通過(guò) @Order 注解或者實(shí)現(xiàn) Ordered 接口來(lái)控制

本文轉(zhuǎn)載自微信公眾號(hào)「貳予三四」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系貳予三四公眾號(hào)。


分享文章:面試問(wèn)爛的SpringAOP,再搞不懂沒(méi)臉回家過(guò)年了……
分享地址:http://www.dlmjj.cn/article/djdooii.html