From 0b2c279b6ebab780d1be688f855ee165a490f16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=84=9F=E5=86=92=E7=81=B5?= Date: Wed, 17 Nov 2021 18:04:46 +0800 Subject: [PATCH] =?UTF-8?q?:=20=E5=BE=AA=E7=8E=AF=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20part=20two?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MethodBeforeAdviceInterceptor.java | 8 +++ .../DefaultAdvisorAutoProxyCreator.java | 67 ++++++++++++------- .../InstantiationAwareBeanPostProcessor.java | 4 ++ .../AbstractAutowiredCapableBeanFactory.java | 31 +++++++-- .../support/DefaultSingletonBeanRegistry.java | 2 +- .../java/cn/noexception/test/ApiRunner.java | 11 +++ .../cn/noexception/test/loop/Husband.java | 23 +++++++ .../noexception/test/loop/HusbandMother.java | 28 ++++++++ .../cn/noexception/test/loop/IMother.java | 11 +++ .../noexception/test/loop/SpouseAdvice.java | 18 +++++ .../java/cn/noexception/test/loop/Wife.java | 32 +++++++++ src/test/resources/spring-loop.xml | 33 +++++++++ 12 files changed, 237 insertions(+), 31 deletions(-) create mode 100644 src/test/java/cn/noexception/test/loop/Husband.java create mode 100644 src/test/java/cn/noexception/test/loop/HusbandMother.java create mode 100644 src/test/java/cn/noexception/test/loop/IMother.java create mode 100644 src/test/java/cn/noexception/test/loop/SpouseAdvice.java create mode 100644 src/test/java/cn/noexception/test/loop/Wife.java create mode 100644 src/test/resources/spring-loop.xml diff --git a/src/main/java/cn/noexception/container/aop/framework/adapter/MethodBeforeAdviceInterceptor.java b/src/main/java/cn/noexception/container/aop/framework/adapter/MethodBeforeAdviceInterceptor.java index 4f1680d..1c9cf69 100644 --- a/src/main/java/cn/noexception/container/aop/framework/adapter/MethodBeforeAdviceInterceptor.java +++ b/src/main/java/cn/noexception/container/aop/framework/adapter/MethodBeforeAdviceInterceptor.java @@ -30,4 +30,12 @@ public class MethodBeforeAdviceInterceptor implements MethodInterceptor { this.advice.before(invocation.getMethod(), invocation.getArguments(), invocation.getThis()); return invocation.proceed(); } + + public MethodBeforeAdvice getAdvice() { + return advice; + } + + public void setAdvice(MethodBeforeAdvice advice) { + this.advice = advice; + } } diff --git a/src/main/java/cn/noexception/container/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java b/src/main/java/cn/noexception/container/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java index cb8a966..661e411 100644 --- a/src/main/java/cn/noexception/container/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java +++ b/src/main/java/cn/noexception/container/aop/framework/autoproxy/DefaultAdvisorAutoProxyCreator.java @@ -14,6 +14,9 @@ import org.aopalliance.intercept.MethodInterceptor; import java.lang.reflect.InvocationTargetException; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; /** * DefaultAdvisorAutoProxyCreator @@ -26,6 +29,8 @@ public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPos private DefaultListableBeanFactory beanFactory; + private final Set earlyProxyReferences = Collections.synchronizedSet(new HashSet<>()); + @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = (DefaultListableBeanFactory) beanFactory; @@ -38,10 +43,45 @@ public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPos @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (isInfrastructureClass(bean.getClass())) return bean; + if (!earlyProxyReferences.contains(beanName)) { + return wrapIfNecessary(bean, beanName); + } + return bean; + } - Collection advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values(); + @Override + public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException { + return null; + } + + @Override + public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { + return true; + } + + /** + * 检测/感知 bean 是否是切点

按需拦截 + */ + private boolean isInfrastructureClass(Class beanClass) { + return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass); + } + + @Override + public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException { + return pvs; + } + @Override + public Object getEarlyBeanReference(Object exposedObject, String beanName) { + earlyProxyReferences.add(beanName); + return wrapIfNecessary(exposedObject, beanName); + } + + protected Object wrapIfNecessary(Object bean, String beanName) { + if (isInfrastructureClass(bean.getClass())) { + return bean; + } + Collection advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values(); for (AspectJExpressionPointcutAdvisor advisor : advisors) { ClassFilter classFilter = advisor.getPointcut().getClassFilter(); // 过滤匹配类 @@ -57,34 +97,15 @@ public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPos // 设置匹配器 advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher()); // 设置选择使用的代理方法 - advisedSupport.setProxyTargetClass(false); + advisedSupport.setProxyTargetClass(true); // 返回代理对象 return new ProxyFactory(advisedSupport).getProxy(); } - return bean; } +} - @Override - public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException { - return null; - } - @Override - public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { - return true; - } - /** - * 检测/感知 bean 是否是切点

按需拦截 - */ - private boolean isInfrastructureClass(Class beanClass) { - return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass); - } - @Override - public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException { - return pvs; - } -} diff --git a/src/main/java/cn/noexception/container/factory/config/InstantiationAwareBeanPostProcessor.java b/src/main/java/cn/noexception/container/factory/config/InstantiationAwareBeanPostProcessor.java index c2e5b2d..61a7577 100644 --- a/src/main/java/cn/noexception/container/factory/config/InstantiationAwareBeanPostProcessor.java +++ b/src/main/java/cn/noexception/container/factory/config/InstantiationAwareBeanPostProcessor.java @@ -33,4 +33,8 @@ public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { * @throws BeansException */ PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException; + + default Object getEarlyBeanReference(Object exposedObject, String beanName){ + return exposedObject; + } } diff --git a/src/main/java/cn/noexception/container/factory/support/AbstractAutowiredCapableBeanFactory.java b/src/main/java/cn/noexception/container/factory/support/AbstractAutowiredCapableBeanFactory.java index b5fb337..0f02df9 100644 --- a/src/main/java/cn/noexception/container/factory/support/AbstractAutowiredCapableBeanFactory.java +++ b/src/main/java/cn/noexception/container/factory/support/AbstractAutowiredCapableBeanFactory.java @@ -34,7 +34,7 @@ public abstract class AbstractAutowiredCapableBeanFactory extends AbstractBeanFa } // 实例化后判断 - boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInitialization(beanName, bean); + boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean); if (!continueWithPropertyPopulation) { return bean; } @@ -62,14 +62,31 @@ public abstract class AbstractAutowiredCapableBeanFactory extends AbstractBeanFa return exposedObject; } - private boolean applyBeanPostProcessorsAfterInitialization(String beanName, Object bean) { - // TODO - return false; + private boolean applyBeanPostProcessorsAfterInstantiation(String beanName, Object bean) { + boolean continueWithPropertyPopulation = true; + for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) { + if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) { + InstantiationAwareBeanPostProcessor instantiationAwareBeanPostProcessor = (InstantiationAwareBeanPostProcessor) beanPostProcessor; + if (!instantiationAwareBeanPostProcessor.postProcessAfterInstantiation(bean, beanName)) { + continueWithPropertyPopulation = false; + break; + } + } + } + + return continueWithPropertyPopulation; } - protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object finalBean) { - // todo - return null; + protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) { + Object exposedObject = bean; + for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) { + if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) { + exposedObject = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).getEarlyBeanReference(exposedObject, beanName); + if (null == exposedObject) + return exposedObject; + } + } + return exposedObject; } @Override diff --git a/src/main/java/cn/noexception/container/factory/support/DefaultSingletonBeanRegistry.java b/src/main/java/cn/noexception/container/factory/support/DefaultSingletonBeanRegistry.java index a36c587..637b00a 100644 --- a/src/main/java/cn/noexception/container/factory/support/DefaultSingletonBeanRegistry.java +++ b/src/main/java/cn/noexception/container/factory/support/DefaultSingletonBeanRegistry.java @@ -40,7 +40,7 @@ public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry { Object singletonObject = singletonObjects.get(beanName); if (null == singletonObject) { singletonObject = earlySingletonObjects.get(beanName); - // 判断耳机缓存中是否有对象,这个对象就是代理对象,因为只有代理对象才会放到三级缓存中 + // 判断二级缓存中是否有对象,这个对象就是代理对象,因为只有代理对象才会放到三级缓存中 if (null == singletonObject) { ObjectFactory singletonFactory = singletonFactories.get(beanName); diff --git a/src/test/java/cn/noexception/test/ApiRunner.java b/src/test/java/cn/noexception/test/ApiRunner.java index 6b9bac5..cc6248a 100644 --- a/src/test/java/cn/noexception/test/ApiRunner.java +++ b/src/test/java/cn/noexception/test/ApiRunner.java @@ -10,6 +10,8 @@ import cn.noexception.test.bean.IUserService; import cn.noexception.test.bean.UserService; import cn.noexception.test.bean.UserServiceInterceptor; import cn.noexception.test.event.CustomEvent; +import cn.noexception.test.loop.Husband; +import cn.noexception.test.loop.Wife; import org.junit.Test; public class ApiRunner { @@ -79,4 +81,13 @@ public class ApiRunner { System.out.println("测试结果:"+userService.queryUserInfo()); } + + @Test + public void test_circular(){ + ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-loop.xml"); + Husband husband = applicationContext.getBean("husband", Husband.class); + Wife wife = applicationContext.getBean("wife", Wife.class); + System.out.println(husband.queryWife()); + System.out.println(wife.queryHusband()); + } } diff --git a/src/test/java/cn/noexception/test/loop/Husband.java b/src/test/java/cn/noexception/test/loop/Husband.java new file mode 100644 index 0000000..9339383 --- /dev/null +++ b/src/test/java/cn/noexception/test/loop/Husband.java @@ -0,0 +1,23 @@ +package cn.noexception.test.loop; + +/** + * Husband + * + * @author 吕滔 + * @Date 2021/11/17 15:10 + */ +public class Husband { + private Wife wife; + + public String queryWife(){ + return "Husband.wife"; + } + + public Wife getWife() { + return wife; + } + + public void setWife(Wife wife) { + this.wife = wife; + } +} diff --git a/src/test/java/cn/noexception/test/loop/HusbandMother.java b/src/test/java/cn/noexception/test/loop/HusbandMother.java new file mode 100644 index 0000000..caa1f23 --- /dev/null +++ b/src/test/java/cn/noexception/test/loop/HusbandMother.java @@ -0,0 +1,28 @@ +package cn.noexception.test.loop; + +import cn.noexception.container.factory.FactoryBean; + +import java.lang.reflect.Proxy; + +/** + * HusbandMother + * + * @author 吕滔 + * @Date 2021/11/17 15:12 + */ +public class HusbandMother implements FactoryBean { + @Override + public IMother getObject() throws Exception { + return (IMother) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IMother.class}, ((proxy, method, args) -> "婚后媳妇妈妈的职责被婆婆代理了!"+method.getName())); + } + + @Override + public Class getObjectType() { + return IMother.class; + } + + @Override + public boolean isSingleton() { + return true; + } +} diff --git a/src/test/java/cn/noexception/test/loop/IMother.java b/src/test/java/cn/noexception/test/loop/IMother.java new file mode 100644 index 0000000..1b2723a --- /dev/null +++ b/src/test/java/cn/noexception/test/loop/IMother.java @@ -0,0 +1,11 @@ +package cn.noexception.test.loop; + +/** + * IMother + * + * @author 吕滔 + * @Date 2021/11/17 15:11 + */ +public interface IMother { + String callMother(); +} diff --git a/src/test/java/cn/noexception/test/loop/SpouseAdvice.java b/src/test/java/cn/noexception/test/loop/SpouseAdvice.java new file mode 100644 index 0000000..d4945d6 --- /dev/null +++ b/src/test/java/cn/noexception/test/loop/SpouseAdvice.java @@ -0,0 +1,18 @@ +package cn.noexception.test.loop; + +import cn.noexception.container.aop.MethodBeforeAdvice; + +import java.lang.reflect.Method; + +/** + * SpouseAdvice + * + * @author 吕滔 + * @Date 2021/11/17 15:15 + */ +public class SpouseAdvice implements MethodBeforeAdvice { + @Override + public void before(Method method, Object[] args, Object target) throws Throwable { + System.out.println("关怀小两口:" + method); + } +} diff --git a/src/test/java/cn/noexception/test/loop/Wife.java b/src/test/java/cn/noexception/test/loop/Wife.java new file mode 100644 index 0000000..58019cc --- /dev/null +++ b/src/test/java/cn/noexception/test/loop/Wife.java @@ -0,0 +1,32 @@ +package cn.noexception.test.loop; + +/** + * Wife + * + * @author 吕滔 + * @Date 2021/11/17 15:10 + */ +public class Wife { + private Husband husband; + private IMother mother; + + public String queryHusband(){ + return "Wife.husband、Mother.callMother: "+mother.callMother(); + } + + public Husband getHusband() { + return husband; + } + + public void setHusband(Husband husband) { + this.husband = husband; + } + + public IMother getMother() { + return mother; + } + + public void setMother(IMother mother) { + this.mother = mother; + } +} diff --git a/src/test/resources/spring-loop.xml b/src/test/resources/spring-loop.xml new file mode 100644 index 0000000..4a864e2 --- /dev/null +++ b/src/test/resources/spring-loop.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- GitLab