Skip to content

Commit f6591b3

Browse files
committed
[Advance][Circular dependency][fix] resolve circular use second third cache
1 parent 7ed4940 commit f6591b3

18 files changed

+338
-30
lines changed

src/main/java/org/m1a2st/aop/AdvisedSupport.java

+52
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package org.m1a2st.aop;
22

33
import org.aopalliance.intercept.MethodInterceptor;
4+
import org.m1a2st.aop.framework.AdvisorChainFactory;
5+
import org.m1a2st.aop.framework.DefaultAdvisorChainFactory;
6+
7+
import java.lang.reflect.Method;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
import java.util.Map;
411

512
/**
613
* @Author m1a2st
@@ -14,6 +21,9 @@ public class AdvisedSupport {
1421
private TargetSource targetSource;
1522
private MethodInterceptor methodInterceptor;
1623
private MethodMatcher methodMatcher;
24+
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
25+
private transient Map<Integer, List<Object>> methodCache;
26+
private List<Advisor> advisors = new ArrayList<>();
1727

1828
public TargetSource getTargetSource() {
1929
return targetSource;
@@ -31,6 +41,10 @@ public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
3141
this.methodInterceptor = methodInterceptor;
3242
}
3343

44+
public void addAdvisor(Advisor advisor) {
45+
advisors.add(advisor);
46+
}
47+
3448
public MethodMatcher getMethodMatcher() {
3549
return methodMatcher;
3650
}
@@ -46,4 +60,42 @@ public boolean isProxyTargetClass() {
4660
public void setProxyTargetClass(boolean proxyTargetClass) {
4761
this.proxyTargetClass = proxyTargetClass;
4862
}
63+
64+
public Map<Integer, List<Object>> getMethodCache() {
65+
return methodCache;
66+
}
67+
68+
public void setMethodCache(Map<Integer, List<Object>> methodCache) {
69+
this.methodCache = methodCache;
70+
}
71+
72+
public AdvisorChainFactory getAdvisorChainFactory() {
73+
return advisorChainFactory;
74+
}
75+
76+
public void setAdvisorChainFactory(AdvisorChainFactory advisorChainFactory) {
77+
this.advisorChainFactory = advisorChainFactory;
78+
}
79+
80+
public List<Advisor> getAdvisors() {
81+
return advisors;
82+
}
83+
84+
public void setAdvisors(List<Advisor> advisors) {
85+
this.advisors = advisors;
86+
}
87+
88+
/**
89+
* 用来返回方法的攔截器鏈
90+
*/
91+
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
92+
Integer cacheKey = method.hashCode();
93+
List<Object> cached = this.methodCache.get(cacheKey);
94+
if (cached == null) {
95+
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
96+
this, method, targetClass);
97+
this.methodCache.put(cacheKey, cached);
98+
}
99+
return cached;
100+
}
49101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.m1a2st.aop;
2+
3+
import org.aopalliance.aop.Advice;
4+
5+
/**
6+
* @Author m1a2st
7+
* @Date 2023/7/26
8+
* @Version v1.0
9+
*/
10+
public interface AfterAdvice extends Advice {
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.m1a2st.aop;
2+
3+
import java.lang.reflect.Method;
4+
5+
/**
6+
* @Author m1a2st
7+
* @Date 2023/7/26
8+
* @Version v1.0
9+
*/
10+
public interface AfterReturningAdvice extends AfterAdvice {
11+
12+
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
13+
}

src/main/java/org/m1a2st/aop/autoproxy/DefaultAdvisorAutoProxyCreator.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.m1a2st.aop.autoproxy;
22

33
import org.aopalliance.aop.Advice;
4-
import org.aopalliance.intercept.MethodInterceptor;
54
import org.m1a2st.aop.*;
65
import org.m1a2st.aop.aspectj.AspectJExpressionPointcutAdvisor;
76
import org.m1a2st.aop.framework.ProxyFactory;
@@ -63,6 +62,7 @@ protected Object wrapIfNecessary(Object bean, String beanName) {
6362
}
6463
Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
6564
try {
65+
ProxyFactory proxyFactory = new ProxyFactory();
6666
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
6767
ClassFilter classFilter = advisor.getPointcut().getClassFilter();
6868
if (classFilter.matches(bean.getClass())) {
@@ -71,11 +71,12 @@ protected Object wrapIfNecessary(Object bean, String beanName) {
7171

7272
// set target source
7373
advisedSupport.setTargetSource(new TargetSource(bean));
74-
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
74+
advisedSupport.addAdvisor(advisor);
7575
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
7676
return new ProxyFactory(advisedSupport).getProxy();
7777
}
7878
}
79+
if (!proxyFactory.getAdvisors().isEmpty()) return proxyFactory.getProxy();
7980
} catch (Exception ex) {
8081
throw new BeansException("Error create proxy bean for: " + beanName, ex);
8182
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.m1a2st.aop.framework;
2+
3+
import org.m1a2st.aop.AdvisedSupport;
4+
5+
import java.lang.reflect.Method;
6+
import java.util.List;
7+
8+
/**
9+
* @Author m1a2st
10+
* @Date 2023/7/26
11+
* @Version v1.0
12+
*/
13+
public interface AdvisorChainFactory {
14+
15+
List<Object> getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport config, Method method, Class<?> targetClass);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.m1a2st.aop.framework;
2+
3+
import org.aopalliance.intercept.MethodInterceptor;
4+
import org.m1a2st.aop.AdvisedSupport;
5+
import org.m1a2st.aop.Advisor;
6+
import org.m1a2st.aop.MethodMatcher;
7+
import org.m1a2st.aop.PointcutAdvisor;
8+
9+
import java.lang.reflect.Method;
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
13+
/**
14+
* @Author m1a2st
15+
* @Date 2023/7/26
16+
* @Version v1.0
17+
*/
18+
public class DefaultAdvisorChainFactory implements AdvisorChainFactory {
19+
20+
@Override
21+
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport config, Method method, Class<?> targetClass) {
22+
Advisor[] advisors = config.getAdvisors().toArray(new Advisor[0]);
23+
List<Object> interceptorList = new ArrayList<>(advisors.length);
24+
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
25+
for (Advisor advisor : advisors) {
26+
if (advisor instanceof PointcutAdvisor) {
27+
// Add it conditionally.
28+
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
29+
// 校驗Advisor是否應用到當前類上
30+
if (pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
31+
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
32+
boolean match;
33+
// 校驗Advisor是否應用到當前方法上
34+
match = mm.matches(method, actualClass);
35+
if (match) {
36+
MethodInterceptor interceptor = (MethodInterceptor) advisor.getAdvice();
37+
interceptorList.add(interceptor);
38+
}
39+
}
40+
}
41+
}
42+
return interceptorList;
43+
}
44+
}

src/main/java/org/m1a2st/aop/framework/JdkDynamicAopProxy.java

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package org.m1a2st.aop.framework;
22

3-
import org.aopalliance.intercept.MethodInterceptor;
43
import org.m1a2st.aop.AdvisedSupport;
54

65
import java.lang.reflect.InvocationHandler;
76
import java.lang.reflect.Method;
87
import java.lang.reflect.Proxy;
8+
import java.util.List;
99

1010
/**
1111
* @Author m1a2st
@@ -22,12 +22,21 @@ public JdkDynamicAopProxy(AdvisedSupport advised) {
2222

2323
@Override
2424
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
25-
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
26-
//代理方法
27-
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
28-
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
25+
// 獲取目標對象
26+
Object target = advised.getTargetSource().getTarget();
27+
Class<?> targetClazz = target.getClass();
28+
Object retVal;
29+
// 獲取攔截器鏈
30+
List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClazz);
31+
if (chain == null || chain.isEmpty()) {
32+
return method.invoke(target, args);
33+
} else {
34+
// 將攔截器統一封裝成ReflectiveMethodInvocation
35+
ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClazz, chain);
36+
// 依次執行每個攔截器的invoke方法
37+
retVal = invocation.proceed();
2938
}
30-
return method.invoke(advised.getTargetSource().getTarget(), args);
39+
return retVal;
3140
}
3241

3342
/**

src/main/java/org/m1a2st/aop/framework/ProxyFactory.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
* @Date 2023/7/16
88
* @Version v1.0
99
*/
10-
public class ProxyFactory {
10+
public class ProxyFactory extends AdvisedSupport {
1111

12-
private final AdvisedSupport advisedSupport;
12+
private AdvisedSupport advisedSupport;
13+
14+
public ProxyFactory() {
15+
}
1316

1417
public ProxyFactory(AdvisedSupport advisedSupport) {
1518
this.advisedSupport = advisedSupport;
@@ -20,7 +23,7 @@ public Object getProxy() {
2023
}
2124

2225
private AopProxy createAopProxy() {
23-
if (advisedSupport.isProxyTargetClass()) {
26+
if (advisedSupport.isProxyTargetClass() || getTargetSource().getTargetClass().length == 0) {
2427
return new AnotherAopProxy(advisedSupport);
2528
}
2629
return new JdkDynamicAopProxy(advisedSupport);

src/main/java/org/m1a2st/aop/framework/ReflectiveMethodInvocation.java

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.m1a2st.aop.framework;
22

3+
import org.aopalliance.intercept.MethodInterceptor;
34
import org.aopalliance.intercept.MethodInvocation;
45

56
import java.lang.reflect.AccessibleObject;
67
import java.lang.reflect.Method;
8+
import java.util.List;
79

810
/**
911
* @Author m1a2st
@@ -12,14 +14,36 @@
1214
*/
1315
public class ReflectiveMethodInvocation implements MethodInvocation {
1416

15-
private final Object target;
16-
private final Method method;
17-
private final Object[] arguments;
17+
protected final Object proxy;
18+
protected final Object target;
19+
protected final Method method;
20+
protected final Object[] arguments;
21+
protected final Class<?> targetClass;
22+
protected final List<Object> interceptorsAndDynamicMethodMatchers;
23+
private int currentInterceptorIndex = -1;
1824

19-
public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) {
25+
public ReflectiveMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> chain) {
26+
this.proxy = proxy;
2027
this.target = target;
2128
this.method = method;
2229
this.arguments = arguments;
30+
this.targetClass = targetClass;
31+
this.interceptorsAndDynamicMethodMatchers = chain;
32+
}
33+
34+
@Override
35+
public Object proceed() throws Throwable {
36+
// 初始currentInterceptorIndex為-1,每調用一次proceed就把currentInterceptorIndex+1
37+
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
38+
// 當調用次數 = 攔截器個數時
39+
// 觸發當前method方法
40+
return method.invoke(this.target, this.arguments);
41+
}
42+
43+
Object interceptorOrInterceptionAdvice =
44+
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
45+
// 普通攔截器,直接觸發攔截器invoke方法
46+
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
2347
}
2448

2549
@Override
@@ -32,10 +56,6 @@ public Object[] getArguments() {
3256
return arguments;
3357
}
3458

35-
@Override
36-
public Object proceed() throws Throwable {
37-
return method.invoke(target, arguments);
38-
}
3959

4060
@Override
4161
public Object getThis() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.m1a2st.aop.framework.adapter;
2+
3+
import org.aopalliance.intercept.MethodInterceptor;
4+
import org.aopalliance.intercept.MethodInvocation;
5+
import org.m1a2st.aop.AfterAdvice;
6+
import org.m1a2st.aop.AfterReturningAdvice;
7+
8+
/**
9+
* @Author m1a2st
10+
* @Date 2023/7/26
11+
* @Version v1.0
12+
*/
13+
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice {
14+
15+
private AfterReturningAdvice advice;
16+
17+
public AfterReturningAdviceInterceptor() {
18+
}
19+
20+
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
21+
this.advice = advice;
22+
}
23+
24+
@Override
25+
public Object invoke(MethodInvocation invocation) throws Throwable {
26+
Object retVal = invocation.proceed();
27+
advice.afterReturning(retVal, invocation.getMethod(), invocation.getArguments(), invocation.getThis());
28+
return retVal;
29+
}
30+
}

src/main/java/org/m1a2st/aop/framework/adapter/MethodBeforeAdviceInterceptor.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33

44
import org.aopalliance.intercept.MethodInterceptor;
55
import org.aopalliance.intercept.MethodInvocation;
6+
import org.m1a2st.aop.BeforeAdvice;
67
import org.m1a2st.aop.MethodBeforeAdvice;
78

89
/**
910
* @Author m1a2st
1011
* @Date 2023/7/16
1112
* @Version v1.0
1213
*/
13-
public class MethodBeforeAdviceInterceptor implements MethodInterceptor {
14+
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice {
1415

1516
private MethodBeforeAdvice advice;
1617

src/main/java/org/m1a2st/beans/factory/config/BeanDefinition.java

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public class BeanDefinition {
2727
private String scope = SCOPE_SINGLETON;
2828
private boolean singleton = true;
2929
private boolean prototype = false;
30+
private boolean lazyInit = false;
3031

3132
public BeanDefinition(Class<?> beanClass, PropertyValues propertyValues) {
3233
this.beanClass = beanClass;
@@ -83,6 +84,14 @@ public boolean isPrototype() {
8384
return prototype;
8485
}
8586

87+
public boolean isLazyInit() {
88+
return lazyInit;
89+
}
90+
91+
public void setLazyInit(boolean lazyInit) {
92+
this.lazyInit = lazyInit;
93+
}
94+
8695
@Override
8796
public boolean equals(Object o) {
8897
if (this == o) return true;

0 commit comments

Comments
 (0)