首先我們先來(lái)一個(gè)簡(jiǎn)單到不能簡(jiǎn)單的服務(wù)接口:
HelloService.java
package com.jd.www.jpl.service;
public interface HelloService {
public void sayHello();
}
以及實(shí)現(xiàn)類
HelloServiceImpl.java
package com.jd.www.jpl.service.impl;
import com.jd.www.jpl.service.HelloService;
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello() {
System.out.println("hello world!!");
}
}
接著創(chuàng)建一個(gè)攔截器接口
Interceptor.java
package com.jd.www.jpl.common.aop.proxy;
public interface Interceptor {
// 前置通知
void before();
// 是否采用環(huán)繞通知
boolean useAround();
// 環(huán)繞通知
Object around(Object target, Method method, Object[] args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
// 事后方法
void after();
// 異常返回方法
void afterThrowing();
// 正常返回方法
void afterReturning();
}
依據(jù)這個(gè)接口乳绕,可以給出一個(gè)很簡(jiǎn)單的實(shí)現(xiàn)
MyInterceptor.java
package com.jd.www.jpl.common.aop.proxy.impl;
import com.jd.www.jpl.common.aop.proxy.Interceptor;
public class MyInterceptor implements Interceptor {
@Override
public void before() {
System.out.println("事前通知");
}
@Override
public boolean useAround() {
return true;
}
@Override
public Object around(Object target, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
System.out.println("環(huán)繞通知before");
Object o = method.invoke(target,args);
System.out.println("環(huán)繞通知after");
return o;
}
@Override
public void after() {
System.out.println("事后通知");
}
@Override
public void afterThrowing() {
System.out.println("異常返回通知");
}
@Override
public void afterReturning() {
System.out.println("正常返回通知");
}
}
如果用proxy去調(diào)用方法借杰,約定如下:
1播演、首先調(diào)用攔截器的before方法翔怎;
2缨伊、如果攔截器的useAround方法,返回為true辣卒,則執(zhí)行攔截器的around方法拧晕,不執(zhí)行target對(duì)象原有的sayHello方法紊扬;
3、無(wú)論結(jié)果如何都會(huì)執(zhí)行攔截器的after方法唉擂;
4餐屎、如果around方法有異常或者原有的target對(duì)象的sayHello方法有異常楔敌,則執(zhí)行攔截器的afterThrowing方法啤挎,否則執(zhí)行afterReturning方法。
好了卵凑,為了更好的說(shuō)明庆聘,我們來(lái)個(gè)流程圖。
對(duì)應(yīng)的ProxyBean
package com.jd.www.jpl.common.aop.proxy.impl;
public class ProxyBean implements InvocationHandler {
private Object target;
private Interceptor interceptor;
public static Object getProxyBean(Object target, Interceptor interceptor){
ProxyBean proxyBean = new ProxyBean();
proxyBean.target = target;
proxyBean.interceptor = interceptor;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),proxyBean);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
boolean e = false;
Object ret = null;
MyInterceptor myInterceptor = new MyInterceptor();
myInterceptor.before();
try {
if(interceptor.useAround()){
ret = myInterceptor.around(target,method,args);
}else {
ret = method.invoke(target,args);
}
} catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException ex) {
e = true;
}
myInterceptor.after();
if(e){
myInterceptor.afterThrowing();
}else{
myInterceptor.afterReturning();
return ret;
}
return null;
}
}
創(chuàng)建測(cè)試用例
SpringAopTest.java
package com.jd.jmq.consumer;
import com.jd.www.jpl.common.aop.proxy.impl.MyInterceptor;
import com.jd.www.jpl.common.aop.proxy.impl.ProxyBean;
import com.jd.www.jpl.service.HelloService;
import com.jd.www.jpl.service.impl.HelloServiceImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:spring/spring-consumer.xml"})
public class SpringAopTest {
@Test
public void testAop(){
HelloService helloService = new HelloServiceImpl();
HelloService proxy = (HelloService) ProxyBean.getProxyBean(helloService,new MyInterceptor());
proxy.sayHello();
}
}
運(yùn)行結(jié)果: