一个建议版本的Spring实现
XML 切点切割放大缩小字体功能 放大缩小字体功能
@Component 订单服务,包括:
/**
* @author mghio
* @since 2021-06-06
*/
@Component(value = "orderService")
public class OrderService {
public void placeOrder() {
System.out.println("place order");
}
}
, 切口位置 ()
<aop:pointcut id="placeOrder" expression="execution(* cn.mghio.service.version5.*.placeOrder(..))"/>
我们需要一个类去表达这个概念,pointcut 要实现的功能是给定一个类的方法,判断是否匹配配置文件中给定的表达式。总的来看 pointcut 由方法匹配器和匹配表达式两部分组成,方法匹配器可以有各种不同的实现,所以是一个接口,pointcut 同样也可以基于多种不同技术实现,故也是一个接口,默认是基于 AspectJ 实现的,类图结构如下:
前卫
/**
* @author mghio
* @since 2021-08-06
*/
public class AspectJExpressionPointcut implements Pointcut, MethodMatcher {
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();
static {
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
}
private String expression;
private ClassLoader pointcutClassLoader;
private PointcutExpression pointcutExpression;
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
@Override
public String getExpression() {
return expression;
}
@Override
public boolean matches(Method method) {
checkReadyToMatch();
ShadowMatch shadowMatch = getShadowMatch(method);
return shadowMatch.alwaysMatches();
}
private void checkReadyToMatch() {
if (Objects.isNull(getExpression())) {
throw new IllegalArgumentException("Must set property 'expression' before attempting to match");
}
if (Objects.isNull(this.pointcutExpression)) {
this.pointcutClassLoader = ClassUtils.getDefaultClassLoader();
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
private PointcutExpression buildPointcutExpression(ClassLoader classLoader) {
PointcutParser pointcutParser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, classLoader);
return pointcutParser.parsePointcutExpression(replaceBooleanOperators(getExpression()));
}
private String replaceBooleanOperators(String pcExpr) {
String result = StringUtils.replace(pcExpr, " and ", " && ");
result = StringUtils.replace(result, " or ", " || ");
result = StringUtils.replace(result, " not ", " ! ");
return result;
}
private ShadowMatch getShadowMatch(Method method) {
ShadowMatch shadowMatch;
try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(method);
} catch (Exception e) {
throw new RuntimeException("not implemented yet");
}
return shadowMatch;
}
// omit other setter、getter ...
}
到这里就完成了给定一个类的方法,判断是否匹配配置文件中给定的表达式的功能。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.e3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/beans/spring-context.xsd">
<context:scann-package base-package="cn.mghio.service.version5,cn.mghio.dao.version5" />
<bean id="tx" class="cn.mghio.tx.TransactionManager"/>
<aop:config>
<aop:aspect ref="tx">
<aop:pointcut id="placeOrder" expression="execution(* cn.mghio.service.version5.*.placeOrder(..))"/>
<aop:before pointcut-ref="placeOrder" method="start"/>
<aop:after-returning pointcut-ref="placeOrder" method="commit"/>
<aop:after-throwing pointcut-ref="placeOrder" method="rollback"/>
</aop:aspect>
</aop:config>
</beans>
在实现各种 XXXAdvice 之前需要定位到这个 Method,比如以上配置文件中的 start、commit、rollback 等方法,为了达到这个目标我们还需要实现的功能就是根据一个 Bean 名称(比如这里的 tx)定位到指定的 Method,然后通过反射调用这个定位到的方法。实际上也比较简单,这个类命名为 MethodLocatingFactory,根据其功能可以定义出目标 Bean 的名称 targetBeanName、需要定位的方法名称 methodName 以及定位完成后得到的方法 method 这三个属性,整体类图结构如下所示:
根据名称和类型定位到方法主要是在 setBeanFactory() 方法中完成的,前提是对应的目标 Bean 名称和方法名称要设置完成,方法定位的类 MethodLocatingFactory 类的代码如下所示:
/**
* @author mghio
* @since 2021-06-06
*/
public class MethodLocatingFactory implements FactoryBean<Method>, BeanFactoryAware {
private String targetBeanName;
private String methodName;
private Method method;
public void setTargetBeanName(String targetBeanName) {
this.targetBeanName = targetBeanName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (!StringUtils.hasText(this.targetBeanName)) {
throw new IllegalArgumentException("Property 'targetBeanName' is required");
}
if (!StringUtils.hasText(this.methodName)) {
throw new IllegalArgumentException("Property 'methodName' is required");
}
Class<?> beanClass = beanFactory.getType(this.targetBeanName);
if (Objects.isNull(beanClass)) {
throw new IllegalArgumentException("Can't determine type of bean with name '" + this.targetBeanName);
}
this.method = BeanUtils.resolveSignature(this.methodName, beanClass);
if (Objects.isNull(this.method)) {
throw new IllegalArgumentException("Unable to locate method [" + this.methodName + "] on bean ["
+ this.targetBeanName + "]");
}
}
@Override
public Method getObject() {
return this.method;
}
@Override
public Class<?> getObjectType() {
return Method.class;
}
}
原文地址:https://www.cnblogs.com/xiaohe0012/p/15209051.html
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(37)-文章发布系统④-百万级数据和千万级数据简单测试
- .Net 转战 Android 4.4 日常笔记(10)--PullToRefresh下拉刷新使用
- .Net 转战 Android 4.4 日常笔记(10)--ADT集成环境更新SDK
- Windows Server 2008R2 配置网络负载平衡(NLB)
- .Net 转战 Android 4.4 日常笔记(9)--常用组件的使用方法[附源码]
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(38)-Easyui-accordion+tree漂亮的菜单导航
- .Net 转战 Android 4.4 日常笔记(8)--常见事件响应及实现方式
- silverlight于javascript通信
- 微信上线小游戏:对流量基础入口应用商店革命
- Appium Desktop 使用
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(36)-文章发布系统③-kindeditor使用
- Windows Server 2008 R2 下配置证书服务器和HTTPS方式访问网站
- .Net 转战 Android 4.4 日常笔记(7)--apk的打包与反编译
- 丰富的silverlight控件
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释