之前实现的自己手写一个AOP动态代理框架(1)只能根据控制器,业务层,DAO层等等注解的形式来进行切面,这里仿Spring,支持AspectJ的表达式进行定位类方法资源,然后进行代理。
集成AspectJ的语法树,即复用AspecJ的对资源的定位功能。也就是说可以使用 execution(* com.fuyouj.service..*.*(..))
这样的表达式。
提供了完整的AOP实现。
定义了切面语法和切面语法的解析。
Spring支持方法级别的织入(满足80%的需求了),AspectJ支持全方位多角度的切面织入。AspectJ学习成本高,所以Spring就没有完整支持所有织入。
导入AspectJ的包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
AspectJ的织入时机
从以上3点来说,理论上AspectJ的效率比Spring要高,毕竟在使用前已经准备好了。而Spring需要新生成一个代理去替换。
实际上我们的使用必须依赖于Spring的容器,容器没有初始化成功,我们就无法使用。但是容器初始化完成,必然AOP也已经完成,我们谁又哪能感受得到这个差距呢?
改造Aspect注解
//作用在类上
@Target(ElementType.TYPE)
//运行时有效
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
//删除
// Class extends Annotation> value() default DefaultAspect.class;
//新增
String pointCut();
}
一个提供解析表示式能力的类
/**
* 解析Aspect表达式 并且定位被织入的目标
*/
public class PointCutLocator {
/**
*AspectJ的 point 解析器
*/
//支持AspectJ的所有表达式
private PointcutParser pointcutParser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
PointcutParser.getAllSupportedPointcutPrimitives()
);
/**
* AspectJ的表达式解析器
*/
private PointcutExpression pointcutExpression;
/**
* 初始化解析表达式
* @param expression
*/
public PointCutLocator(String expression){
pointcutExpression = pointcutParser.parsePointcutExpression(expression);
}
/**粗筛
* @param targetClass
* @return 是否匹配
*/
public boolean roughMatches(Class<?> targetClass){
//只能校验 withIn表达式 对于不能校验的 execution表达式,默认返回true 所以这里是粗筛
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
/**精确筛选
*判断传入的 Method对象是否是Aspect的目标代理方法,即精确匹配PointCut
* @param method
* @return
*/
public boolean accurateMatches(Method method){
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
return shadowMatch.alwaysMatches();
}
}
先说说思路。
1.获取容器里面所有的切面类
2.拼接好切面描述类集合
3.遍历容器的类,为符合被代理条件的类创建初筛后的集合
4.对每个类尝试织入,织入的时候精确筛选。
改造AspectInfo,支持复用AspectJ的解析能力。
@Data
public class AspectInfo {
private int orderIndex;
private DefaultAspect aspectObject;
//复用AspectJ
private PointCutLocator pointCutLocator;
public AspectInfo() {
}
public AspectInfo(int orderIndex, DefaultAspect aspectObject) {
this.orderIndex = orderIndex;
this.aspectObject = aspectObject;
}
public AspectInfo(int orderIndex, DefaultAspect aspectObject, PointCutLocator pointCutLocator) {
this.orderIndex = orderIndex;
this.aspectObject = aspectObject;
this.pointCutLocator = pointCutLocator;
}
}
public class AspectWeaver {
private BeanContainer beanContainer;
public AspectWeaver(){
beanContainer = BeanContainer.getInstance();
}
public void doAopByAspectJ(){
//1.获取所有的切面类
Set<Class<?>> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);
//非空判断
if (ValidationUtil.isEmpty(aspectSet)){return;}
//初始化切面描述类集合
List<AspectInfo> aspectInfoList = packAspectInfoList(aspectSet);
//遍历容器里面所有的类
Set<Class<?>> classes = beanContainer.getClasses();
//初筛 判断这些切面类的是否是为这个类服务的 留下每个类粗筛后的结果
List<AspectInfo> roughMatchAspectList = collectRoughMatchedAspectListForSpecificClass(aspectInfoList,targetClass);
//对每个类粗筛后的 尝试织入
wrapIfNecessary(roughMatchAspectList,targetClass);
然后补充上出现的方法。
/**拼接切面描述类List
* @param aspectSet
* @return
*/
private List<AspectInfo> packAspectInfoList(Set<Class<?>> aspectSet) {
List<AspectInfo> aspectInfoList = new ArrayList<>();
for (Class<?> aspectClass : aspectSet) {
if (verifyAspect(aspectClass)){
Order orderTag = aspectClass.getAnnotation(Order.class);
Aspect aspectTag = aspectClass.getAnnotation(Aspect.class);
DefaultAspect defaultAspect = (DefaultAspect) beanContainer.getBean(aspectClass);
//初始化表达式定位器
PointCutLocator pointCutLocator = new PointCutLocator(aspectTag.pointCut());
AspectInfo aspectInfo = new AspectInfo(orderTag.value(),defaultAspect,pointCutLocator);
//添加进列表
aspectInfoList.add(aspectInfo);
}else {
throw new RuntimeException("当前切面类必须持有@Aspect和 @Order 和继承自DefaultAspect,且符合规范");
}
}
return aspectInfoList;
}
/**
* 初筛
* @param aspectInfoList
* @param targetClass
* @return 返回初筛后的列表
*/
private List<AspectInfo> collectRoughMatchedAspectListForSpecificClass(List<AspectInfo> aspectInfoList, Class<?> targetClass) {
List<AspectInfo> roughMatchAspectList = new ArrayList<>();
if (ValidationUtil.isEmpty(aspectInfoList)){return roughMatchAspectList;}
for (AspectInfo aspectInfo : aspectInfoList) {
//初筛
boolean matches = aspectInfo.getPointCutLocator().roughMatches(targetClass);
//如果匹配 就加入
if (matches){
roughMatchAspectList.add(aspectInfo);
}
}
return roughMatchAspectList;
}
/**
* 尝试织入逻辑
* @param roughMatchAspectList
* @param targetClass
*/
private void wrapIfNecessary(List<AspectInfo> roughMatchAspectList, Class<?> targetClass) {
if (ValidationUtil.isEmpty(roughMatchAspectList)){
return;
}
//创建动态代理对象
AspectListExecutor executor = new AspectListExecutor(targetClass,roughMatchAspectList);
Object proxyBean = ProxyCreator.createProxy(targetClass, executor);
//替换被代理的对象
beanContainer.addBean(targetClass,proxyBean);
}
精确筛选的逻辑放在AspectListExecutor里面
/**
* 网被代理的方法添加横切逻辑
*/
@Data
@NoArgsConstructor
public class AspectListExecutor implements MethodInterceptor {
//被代理的class
private Class<?> targetClass;
//切面信息集合 照顾多个AOP的 情况
private List<AspectInfo> sortedAspectInfoList;
public AspectListExecutor(Class<?> targetClass,List<AspectInfo> aspectInfos){
this.targetClass = targetClass;
this.sortedAspectInfoList = sort(aspectInfos);
}
private List<AspectInfo> sort(List<AspectInfo> aspectInfos) {
//升序排列
Collections.sort(aspectInfos, new Comparator<AspectInfo>() {
@Override
public int compare(AspectInfo o1, AspectInfo o2) {
return o1.getOrderIndex() - o2.getOrderIndex();
}
});
return aspectInfos;
}
/**
*
* @param o 被增强的对象
* @param method 需要拦截的方法
* @param args 方法参数
* @param methodProxy 代理方法
* @return 返回值
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 2.0 代码 精确筛选
collectAccurateMatchAspectList(method);
Object returnValue = null;
if (ValidationUtil.isEmpty(sortedAspectInfoList)){
//就算为空也要执行原来的方法啊
return methodProxy.invokeSuper(o,args);
}
//1.按照order的顺序执行完毕所有切面的before方法
invokeBeforeAdvices(method,args);
try {
//2。 执行被代理的方法
returnValue = methodProxy.invokeSuper(o,args);
//3. 如果被代理方法正常返回,按照order的顺序 逆序执行afterReturning
returnValue = invokeAfterReturningAdvices(method,args,returnValue);
}catch (Exception e){
//执行异常时
invokeAfterThrowingAdvices(method,args,e);
}
return returnValue;
}
/**
* 精确匹配 留下符合精确匹配的结果
* @param method
*/
private void collectAccurateMatchAspectList(Method method) {
if(ValidationUtil.isEmpty(sortedAspectInfoList)){return;}
Iterator<AspectInfo> iterator = sortedAspectInfoList.iterator();
while (iterator.hasNext()){
AspectInfo aspectInfo = iterator.next();
//区别两种方式
//如果注解不为空 校验注解
//精确校验
if (aspectInfo.getPointCutLocator().accurateMatches(method) == false){
iterator.remove();
}
}
}
/**
* 发生异常的时候执行 降序
* @param method
* @param args
* @param e
*/
private void invokeAfterThrowingAdvices(Method method, Object[] args, Exception e) throws Throwable {
for (int i = sortedAspectInfoList.size() -1; i >=0 ; i--) {
sortedAspectInfoList.get(i).getAspectObject()
.afterThrowing(targetClass,method,args,e);
}
}
/**
* 如果代理方法正常返回,降序执行afterAdvice
* @param method
* @param args
* @param returnValue
* @return
*/
private Object invokeAfterReturningAdvices(Method method, Object[] args, Object returnValue) throws Throwable {
Object res = null;
for (int i = sortedAspectInfoList.size()-1; i >=0 ; i--) {
res = sortedAspectInfoList.get(i).getAspectObject().afterReturning(targetClass, method, args, returnValue);
}
return res;
}
/**
* 按照oder的 顺序升序执行
* @param method
* @param args
*/
private void invokeBeforeAdvices(Method method, Object[] args) throws Throwable {
for (AspectInfo info : sortedAspectInfoList) {
info.getAspectObject().before(targetClass,method,args);
}
}
}
改写原来的测试类
package com.fuyouj.aspect.test;
import com.framework.aop.annotation.Aspect;
import com.framework.aop.annotation.Order;
import com.framework.aop.aspect.DefaultAspect;
import com.framework.core.annotation.Controller;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
/**
* @Desc
* @Author FuYouJ
* @date 2020/6/2 0:40
*/
@Aspect(pointCut = "execution(* com.fuyouj.controller..*.*(..))")
@Order(0)
@Slf4j
public class TestAopOne extends DefaultAspect {
@Override
public void before(Class<?> targetClass, Method method, Object[] args) throws Throwable {
log.info("我是切面逻辑before order0,我增强的目标类是{},我增强的目标方法是{},方法参数{}"
,targetClass.getSimpleName(),method.getName(),args);
}
@Override
public Object afterReturning(Class<?> targetClass, Method method, Object[] args, Object returnValue) throws Throwable {
Integer res = (Integer) returnValue;
log.info("我是切面逻辑after order0,我增强的目标类是{},我增强的目标方法是{},方法参数{}"
,targetClass.getSimpleName(),method.getName(),args);
res++;
return res;
}
}
package com.fuyouj.aspect.test;
import com.framework.aop.annotation.Aspect;
import com.framework.aop.annotation.Order;
import com.framework.aop.aspect.DefaultAspect;
import com.framework.core.annotation.Controller;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
/**
* @Desc
* @Author FuYouJ
* @date 2020/6/2 0:40
*/
@Aspect(pointCut = "execution(* com.fuyouj.controller..*.*(..))")
@Order(1)
@Slf4j
public class TestAopTwo extends DefaultAspect {
@Override
public void before(Class<?> targetClass, Method method, Object[] args) throws Throwable {
log.info("我是切面逻辑before order1,我增强的目标类是{},我增强的目标方法是,方法参数{}"
,targetClass.getSimpleName(),method.getName(),args);
}
@Override
public Object afterReturning(Class<?> targetClass, Method method, Object[] args, Object returnValue) throws Throwable {
Integer res = (Integer) returnValue;
log.info("我是切面逻辑after order1,我增强的目标类是{},我增强的目标方法是,方法参数{}"
,targetClass.getSimpleName(),method.getName(),args);
res++;
return res;
}
}
测试用例
public class TestAop {
@DisplayName("测试第二个版本的AOP")
@Test
public void testAopOne(){
BeanContainer beanContainer = BeanContainer.getInstance();
//加载了所有类
beanContainer.loadBeans("com.fuyouj");
//AOP
new AspectWeaver().doAopByAspectJ();
// ioc
new DependencyInjector().doIoc();
TestAopController controller = (TestAopController) beanContainer.getBean(TestAopController.class);
int say = controller.say();
System.out.println("======================================返回结果======="+say+"======");
}
}
可以将DefaultAspect这个抽象类改造成接口,因为java只能继承一个类,为了减轻实现的压力。使用 Default关键字。代码是一样可以运行的。
package com.framework.aop.aspect;
/**
* @Desc
* @Author FuYouJ
* @date 2020/5/31 21:24
*/
import java.lang.reflect.Method;
/**
* 定义切面的通用骨架
* 通过钩子方法实现
*/
public interface DefaultAspect {
/**
* @param targetClass 被代理的目标类型
* @param method 被代理的方法
* @param args 方法的参数
* @throws Throwable
*/
default void before(Class<?> targetClass, Method method,Object[] args) throws Throwable{
} ;
/**
*
* @param targetClass 被代理的目标类型
* @param method 被代理的方法
* @param args 方法的参数
* @param returnValue 返回值
* @return
* @throws Throwable
*/
default Object afterReturning(Class<?> targetClass,Method method
,Object[] args,Object returnValue) throws Throwable{
return returnValue;
}
/**
*
* @param targetClass 被代理的目标类型
* @param method 被代理的方法
* @param args 方法的参数
* @param e 异常
* @throws Throwable
*/
default void afterThrowing(Class<?> targetClass,
Method method,Object[] args,Throwable e) throws Throwable{
}
}