最近做項(xiàng)目需要使用切面技術(shù)假褪,對(duì)已有系統(tǒng)使用的組件進(jìn)行切面攔截入?yún)⒑统鰠⑷鳎崂硐虏煌忻婕夹g(shù)的使用和差別。
Spring Aop
特點(diǎn)
- 動(dòng)態(tài)代理的方式實(shí)現(xiàn)Aop,接口類型通過JDK代理實(shí)現(xiàn),非接口類型通過cglib代理實(shí)現(xiàn)
- 只能切面Spring管理的bean
- 運(yùn)行時(shí)織入
- 針對(duì)bean自身的接口無法使用代理堪嫂,故無法進(jìn)行切面
使用方式
基于Springboot,調(diào)用DB Service接口時(shí)進(jìn)行代理配置窄锅,這樣就可以做到根據(jù)不同的環(huán)境配置不同的代理
@SpringBootApplication
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableScheduling
@MapperScan("com.xx.ci.dtw.dto.dao")
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
切面實(shí)現(xiàn)
@Component
public class DBPrxoyAspect {
private final static Logger logger = LoggerFactory.getLogger(DBPrxoyAspect.class);
@Value("${socksProxyHost}")
private String socksProxyHost;
@Value("${socksProxyPort}")
private String socksProxyPort;
@Pointcut("execution(public * com.xx.ci.dtw.service..*.*(..))")
public void serviceDbAop() {
}
@Before("serviceDbAop()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
Properties prop = System.getProperties();
prop.setProperty("socksProxyHost", socksProxyHost);
prop.setProperty("socksProxyPort", socksProxyPort);
logger.debug("add db proxy, socksProxyHost={}, socksProxyPort={}", socksProxyHost, socksProxyPort);
}
@org.aspectj.lang.annotation.After("serviceDbAop()")
public void After(JoinPoint joinPoint) throws Throwable {
Properties prop = System.getProperties();
prop.setProperty("socksProxyHost", "");
prop.setProperty("socksProxyPort", "");
logger.debug("release db proxy, socksProxyHost={}, socksProxyPort={}", socksProxyHost, socksProxyPort);
}
}
AspectJ
特點(diǎn)
Spring Aop 很多地方都是直接用到AspectJ里面的代碼创千。典型的比如@Aspect,@Around入偷,@Pointcut注解等等追驴。而且從相關(guān)概念以及語法結(jié)構(gòu)上而言,兩者其實(shí)非常非常相似
最大的區(qū)別在于兩者實(shí)現(xiàn)AOP的底層原理不太一樣:
Spring AOP: 基于代理(Proxying)
AspectJ: 基于字節(jié)碼操作(Bytecode Manipulation)
使用方式
參考:https://github.com/medvedev1088/aspectj-load-time-weaving-example
- 實(shí)現(xiàn)切面功能
@Aspect
public class DateTimeToStringAspect {
public static final String TO_STRING_RESULT = "test";
@Pointcut("execution(* org.joda.time.base.AbstractDateTime.toString())")
public void dateTimeToString() {
}
@Around("dateTimeToString()")
public Object toLowerCase(ProceedingJoinPoint joinPoint) throws Throwable {
Object ignoredToStringResult = joinPoint.proceed();
System.out.println("DateTime#toString() has been invoked: " + ignoredToStringResult);
return TO_STRING_RESULT;
}
}
2.配置切面和切點(diǎn)信息
<aspectj>
<aspects>
<!-- Aspects -->
<aspect name="com.example.aspectj.DateTimeToStringAspect"/>
</aspects>
<weaver options="-verbose -showWeaveInfo">
<include within="org.joda.time.base.AbstractDateTime"/>
</weaver>
</aspectj>
3疏之、使用javaagent實(shí)現(xiàn)classloader加載時(shí)織入
啟動(dòng)運(yùn)行時(shí)增加vm的代理配置
若是使用Idea 直接run 則需要配置Edit Configration 增加VM配置:
-javaagent:/Users/sherrichen/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar
jar的運(yùn)行方式增加代理
java -javaagent:/Users/sherrichen/.m2/repository/org/aspectj/aspectjweaver//1.8.13/aspectjweaver-1.8.13.jar -jar target/aspectj-ltw-example-1.0-SNAPSHOT.jar