Skip to content

Commit

Permalink
[Advance][Circular dependency][fix] resolve circular use second third…
Browse files Browse the repository at this point in the history
… cache
  • Loading branch information
m1a2st committed Dec 10, 2023
1 parent 7ed4940 commit f6591b3
Show file tree
Hide file tree
Showing 18 changed files with 338 additions and 30 deletions.
52 changes: 52 additions & 0 deletions src/main/java/org/m1a2st/aop/AdvisedSupport.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package org.m1a2st.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.m1a2st.aop.framework.AdvisorChainFactory;
import org.m1a2st.aop.framework.DefaultAdvisorChainFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
* @Author m1a2st
Expand All @@ -14,6 +21,9 @@ public class AdvisedSupport {
private TargetSource targetSource;
private MethodInterceptor methodInterceptor;
private MethodMatcher methodMatcher;
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
private transient Map<Integer, List<Object>> methodCache;
private List<Advisor> advisors = new ArrayList<>();

public TargetSource getTargetSource() {
return targetSource;
Expand All @@ -31,6 +41,10 @@ public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
this.methodInterceptor = methodInterceptor;
}

public void addAdvisor(Advisor advisor) {
advisors.add(advisor);
}

public MethodMatcher getMethodMatcher() {
return methodMatcher;
}
Expand All @@ -46,4 +60,42 @@ public boolean isProxyTargetClass() {
public void setProxyTargetClass(boolean proxyTargetClass) {
this.proxyTargetClass = proxyTargetClass;
}

public Map<Integer, List<Object>> getMethodCache() {
return methodCache;
}

public void setMethodCache(Map<Integer, List<Object>> methodCache) {
this.methodCache = methodCache;
}

public AdvisorChainFactory getAdvisorChainFactory() {
return advisorChainFactory;
}

public void setAdvisorChainFactory(AdvisorChainFactory advisorChainFactory) {
this.advisorChainFactory = advisorChainFactory;
}

public List<Advisor> getAdvisors() {
return advisors;
}

public void setAdvisors(List<Advisor> advisors) {
this.advisors = advisors;
}

/**
* 用来返回方法的攔截器鏈
*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
Integer cacheKey = method.hashCode();
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
}
11 changes: 11 additions & 0 deletions src/main/java/org/m1a2st/aop/AfterAdvice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.m1a2st.aop;

import org.aopalliance.aop.Advice;

/**
* @Author m1a2st
* @Date 2023/7/26
* @Version v1.0
*/
public interface AfterAdvice extends Advice {
}
13 changes: 13 additions & 0 deletions src/main/java/org/m1a2st/aop/AfterReturningAdvice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.m1a2st.aop;

import java.lang.reflect.Method;

/**
* @Author m1a2st
* @Date 2023/7/26
* @Version v1.0
*/
public interface AfterReturningAdvice extends AfterAdvice {

void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.m1a2st.aop.autoproxy;

import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.m1a2st.aop.*;
import org.m1a2st.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.m1a2st.aop.framework.ProxyFactory;
Expand Down Expand Up @@ -63,6 +62,7 @@ protected Object wrapIfNecessary(Object bean, String beanName) {
}
Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
try {
ProxyFactory proxyFactory = new ProxyFactory();
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
ClassFilter classFilter = advisor.getPointcut().getClassFilter();
if (classFilter.matches(bean.getClass())) {
Expand All @@ -71,11 +71,12 @@ protected Object wrapIfNecessary(Object bean, String beanName) {

// set target source
advisedSupport.setTargetSource(new TargetSource(bean));
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.addAdvisor(advisor);
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
return new ProxyFactory(advisedSupport).getProxy();
}
}
if (!proxyFactory.getAdvisors().isEmpty()) return proxyFactory.getProxy();
} catch (Exception ex) {
throw new BeansException("Error create proxy bean for: " + beanName, ex);
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/m1a2st/aop/framework/AdvisorChainFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.m1a2st.aop.framework;

import org.m1a2st.aop.AdvisedSupport;

import java.lang.reflect.Method;
import java.util.List;

/**
* @Author m1a2st
* @Date 2023/7/26
* @Version v1.0
*/
public interface AdvisorChainFactory {

List<Object> getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport config, Method method, Class<?> targetClass);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.m1a2st.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.m1a2st.aop.AdvisedSupport;
import org.m1a2st.aop.Advisor;
import org.m1a2st.aop.MethodMatcher;
import org.m1a2st.aop.PointcutAdvisor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
* @Author m1a2st
* @Date 2023/7/26
* @Version v1.0
*/
public class DefaultAdvisorChainFactory implements AdvisorChainFactory {

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport config, Method method, Class<?> targetClass) {
Advisor[] advisors = config.getAdvisors().toArray(new Advisor[0]);
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 校驗Advisor是否應用到當前類上
if (pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 校驗Advisor是否應用到當前方法上
match = mm.matches(method, actualClass);
if (match) {
MethodInterceptor interceptor = (MethodInterceptor) advisor.getAdvice();
interceptorList.add(interceptor);
}
}
}
}
return interceptorList;
}
}
21 changes: 15 additions & 6 deletions src/main/java/org/m1a2st/aop/framework/JdkDynamicAopProxy.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.m1a2st.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.m1a2st.aop.AdvisedSupport;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

/**
* @Author m1a2st
Expand All @@ -22,12 +22,21 @@ public JdkDynamicAopProxy(AdvisedSupport advised) {

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
//代理方法
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
// 獲取目標對象
Object target = advised.getTargetSource().getTarget();
Class<?> targetClazz = target.getClass();
Object retVal;
// 獲取攔截器鏈
List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClazz);
if (chain == null || chain.isEmpty()) {
return method.invoke(target, args);
} else {
// 將攔截器統一封裝成ReflectiveMethodInvocation
ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClazz, chain);
// 依次執行每個攔截器的invoke方法
retVal = invocation.proceed();
}
return method.invoke(advised.getTargetSource().getTarget(), args);
return retVal;
}

/**
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/org/m1a2st/aop/framework/ProxyFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
* @Date 2023/7/16
* @Version v1.0
*/
public class ProxyFactory {
public class ProxyFactory extends AdvisedSupport {

private final AdvisedSupport advisedSupport;
private AdvisedSupport advisedSupport;

public ProxyFactory() {
}

public ProxyFactory(AdvisedSupport advisedSupport) {
this.advisedSupport = advisedSupport;
Expand All @@ -20,7 +23,7 @@ public Object getProxy() {
}

private AopProxy createAopProxy() {
if (advisedSupport.isProxyTargetClass()) {
if (advisedSupport.isProxyTargetClass() || getTargetSource().getTargetClass().length == 0) {
return new AnotherAopProxy(advisedSupport);
}
return new JdkDynamicAopProxy(advisedSupport);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.m1a2st.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.List;

/**
* @Author m1a2st
Expand All @@ -12,14 +14,36 @@
*/
public class ReflectiveMethodInvocation implements MethodInvocation {

private final Object target;
private final Method method;
private final Object[] arguments;
protected final Object proxy;
protected final Object target;
protected final Method method;
protected final Object[] arguments;
protected final Class<?> targetClass;
protected final List<Object> interceptorsAndDynamicMethodMatchers;
private int currentInterceptorIndex = -1;

public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) {
public ReflectiveMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> chain) {
this.proxy = proxy;
this.target = target;
this.method = method;
this.arguments = arguments;
this.targetClass = targetClass;
this.interceptorsAndDynamicMethodMatchers = chain;
}

@Override
public Object proceed() throws Throwable {
// 初始currentInterceptorIndex為-1,每調用一次proceed就把currentInterceptorIndex+1
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 當調用次數 = 攔截器個數時
// 觸發當前method方法
return method.invoke(this.target, this.arguments);
}

Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 普通攔截器,直接觸發攔截器invoke方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

@Override
Expand All @@ -32,10 +56,6 @@ public Object[] getArguments() {
return arguments;
}

@Override
public Object proceed() throws Throwable {
return method.invoke(target, arguments);
}

@Override
public Object getThis() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.m1a2st.aop.framework.adapter;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.m1a2st.aop.AfterAdvice;
import org.m1a2st.aop.AfterReturningAdvice;

/**
* @Author m1a2st
* @Date 2023/7/26
* @Version v1.0
*/
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice {

private AfterReturningAdvice advice;

public AfterReturningAdviceInterceptor() {
}

public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
this.advice = advice;
}

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object retVal = invocation.proceed();
advice.afterReturning(retVal, invocation.getMethod(), invocation.getArguments(), invocation.getThis());
return retVal;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.m1a2st.aop.BeforeAdvice;
import org.m1a2st.aop.MethodBeforeAdvice;

/**
* @Author m1a2st
* @Date 2023/7/16
* @Version v1.0
*/
public class MethodBeforeAdviceInterceptor implements MethodInterceptor {
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice {

private MethodBeforeAdvice advice;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class BeanDefinition {
private String scope = SCOPE_SINGLETON;
private boolean singleton = true;
private boolean prototype = false;
private boolean lazyInit = false;

public BeanDefinition(Class<?> beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
Expand Down Expand Up @@ -83,6 +84,14 @@ public boolean isPrototype() {
return prototype;
}

public boolean isLazyInit() {
return lazyInit;
}

public void setLazyInit(boolean lazyInit) {
this.lazyInit = lazyInit;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Loading

0 comments on commit f6591b3

Please sign in to comment.