spring自定义切面实现拦截类全方法
前言
我先问一个spring aop是否生效问题,伪代码如下
// 父类
class P {
public void pr(){
print('is pr')
}
}
// 子类
@compont
class S{
}
@compont
class D{
@Autowired
S s;
void ss(){
s.pr()
}
}
你有啥办法能切到pr() 方法?
这里有朋友应该会说直接把父类的所有方法做个切面
这样能实现,但是不好
因为我只是想切S类的所有方法,包括其父类,甚至父类的父类
代码思路
本来我也是放弃了,这两天在学习事务注解源码的过程中我又找到了新的思路
BeanFactoryTransactionAttributeSourceAdvisor
继承了AbstractPointcutAdvisor
将切面逻辑注入到spring 中
TransactionAttributeSourcePointcut
最主要就是判断bean在调用方法时切面是否符合
TransactionInterceptor
是切面的主要运行逻辑
那么BeanFactoryTransactionAttributeSourceAdvisor
如何注入spring的,之前的文章没有讲,这里我补充下
我们从org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 所有切面增强器
// 最终调用 BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 所有符合条件的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 扩展
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
public List<Advisor> findAdvisorBeans() {
// 缓存数据
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 从当前容器中找所有 实现 Advisor 的类
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
....
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
.....
}
}
}
}
return advisors;
}
那么此时在看看BeanFactoryTransactionAttributeSourceAdvisor
定义,其实最终也是实现了Advisor
接口
而其中AbstractBeanFactoryPointcutAdvisor
这个实现了大部分方法,我们也只需要集成这个抽象类即可
代码实现
切面判断
@Slf4j
public class DbSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
@Override
public boolean matches(Method method, @Nullable Class<?> targetClass) {
if (targetClass == null) {
return false;
}
Class<?> declaringClass = method.getDeclaringClass();
String superClassName = declaringClass.getName();
if (!targetClass.getName().equals("com.impl.S")){
// 不是S类的方法不进切面
return false;
}
return superClassName.equals("com.impl.S") || superClassName.equals("com.impl.P");
}
}
拦截器
/**
* 系统数据库操作处理切面
*/
@Slf4j
public class SysDbInterceptor implements MethodInterceptor, Serializable {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 增强处理
Object proceed;
try {
proceed = invocation.proceed();
} finally {
.......
}
return proceed;
}
}
注入spiring
@Component
public class DbPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor {
DbSourcePointcut pointcut = new DbSourcePointcut();
public DbPointcutAdvisor() {
setAdvice(new SysDbInterceptor());
}
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return pointcut;
}
}
转载自:https://juejin.cn/post/7000240324140351525