diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e95151 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +target/ +tiny-spring.iml diff --git a/pom.xml b/pom.xml index 00fe1de..3eadfe3 100644 --- a/pom.xml +++ b/pom.xml @@ -29,10 +29,15 @@ + + org.projectlombok + lombok + 1.16.18 + junit junit - 4.7 + 4.12 test @@ -59,8 +64,8 @@ maven-compiler-plugin 3.1 - 1.6 - 1.6 + 1.8 + 1.8 UTF-8 @@ -85,6 +90,7 @@ + diff --git a/src/main/java/us/codecraft/tinyioc/aop/AspectJAwareAdvisorAutoProxyCreator.java b/src/main/java/us/codecraft/tinyioc/aop/AspectJAwareAdvisorAutoProxyCreator.java index e1ce4d9..d82e1af 100644 --- a/src/main/java/us/codecraft/tinyioc/aop/AspectJAwareAdvisorAutoProxyCreator.java +++ b/src/main/java/us/codecraft/tinyioc/aop/AspectJAwareAdvisorAutoProxyCreator.java @@ -10,15 +10,18 @@ /** * @author yihua.huang@dianping.com */ +// 本身就是一个Bean public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware { private AbstractBeanFactory beanFactory; + //初始化之前的一次回调 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception { return bean; } + //初始化后的一次回调 对所有的bean做一次增强 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { if (bean instanceof AspectJExpressionPointcutAdvisor) { @@ -27,9 +30,12 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw if (bean instanceof MethodInterceptor) { return bean; } - List advisors = beanFactory - .getBeansForType(AspectJExpressionPointcutAdvisor.class); + /* + 此处获得advisor,由advisor来负责判断当前传入的bean是否需要被增强 + */ + List advisors = beanFactory.getBeansForType(AspectJExpressionPointcutAdvisor.class); for (AspectJExpressionPointcutAdvisor advisor : advisors) { + //advisor匹配 if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) { ProxyFactory advisedSupport = new ProxyFactory(); advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); @@ -38,12 +44,15 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces()); advisedSupport.setTargetSource(targetSource); + //此时返回的是CGLib代理的对象 并非原始的对象 return advisedSupport.getProxy(); } } return bean; } + //初始化的时候 注入beanFactory + //在beanPostProcessor接口回调的时候 使用beanFactory的引用 @Override public void setBeanFactory(BeanFactory beanFactory) throws Exception { this.beanFactory = (AbstractBeanFactory) beanFactory; diff --git a/src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java b/src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java index 8e69d69..1174378 100644 --- a/src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java +++ b/src/main/java/us/codecraft/tinyioc/aop/AspectJExpressionPointcut.java @@ -18,6 +18,7 @@ public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodM private String expression; + //切点表达式 private PointcutExpression pointcutExpression; private static final Set DEFAULT_SUPPORTED_PRIMITIVES = new HashSet(); diff --git a/src/main/java/us/codecraft/tinyioc/aop/BeanFactoryAware.java b/src/main/java/us/codecraft/tinyioc/aop/BeanFactoryAware.java index e29a8c6..d0da8b4 100644 --- a/src/main/java/us/codecraft/tinyioc/aop/BeanFactoryAware.java +++ b/src/main/java/us/codecraft/tinyioc/aop/BeanFactoryAware.java @@ -5,6 +5,11 @@ /** * @author yihua.huang@dianping.com */ + +/* + 此接口主要的目的,是将BeanFactory的引用 注入进一些特殊的bean中,例如 BeanProcessor的实现 + AspectJAwareAdvisorAutoProxyCreator 需要处理一些AOP相关的代理 + */ public interface BeanFactoryAware { void setBeanFactory(BeanFactory beanFactory) throws Exception; diff --git a/src/main/java/us/codecraft/tinyioc/aop/Cglib2AopProxy.java b/src/main/java/us/codecraft/tinyioc/aop/Cglib2AopProxy.java index 4831097..d3c121b 100644 --- a/src/main/java/us/codecraft/tinyioc/aop/Cglib2AopProxy.java +++ b/src/main/java/us/codecraft/tinyioc/aop/Cglib2AopProxy.java @@ -36,8 +36,10 @@ private DynamicAdvisedInterceptor(AdvisedSupport advised) { this.delegateMethodInterceptor = advised.getMethodInterceptor(); } + // 代理对象 @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + // 如果match匹配到 那么代理 if (advised.getMethodMatcher() == null || advised.getMethodMatcher().matches(method, advised.getTargetSource().getTargetClass())) { return delegateMethodInterceptor.invoke(new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy)); @@ -46,6 +48,7 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr } } + // 创建一个原始的方法调用 private static class CglibMethodInvocation extends ReflectiveMethodInvocation { private final MethodProxy methodProxy; diff --git a/src/main/java/us/codecraft/tinyioc/aop/JdkDynamicAopProxy.java b/src/main/java/us/codecraft/tinyioc/aop/JdkDynamicAopProxy.java index 4667cd2..bf28610 100644 --- a/src/main/java/us/codecraft/tinyioc/aop/JdkDynamicAopProxy.java +++ b/src/main/java/us/codecraft/tinyioc/aop/JdkDynamicAopProxy.java @@ -13,6 +13,7 @@ */ public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler { + // advisedSupport 调用实际方法前 调用hook方法 , 标明需要 拦截哪些方法 public JdkDynamicAopProxy(AdvisedSupport advised) { super(advised); } @@ -27,6 +28,7 @@ public Object invoke(final Object proxy, final Method method, final Object[] arg MethodInterceptor methodInterceptor = advised.getMethodInterceptor(); if (advised.getMethodMatcher() != null && advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) { + // 执行拦截的方法 , 由拦截的方法负责调用 真实的bean方法 return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args)); } else { diff --git a/src/main/java/us/codecraft/tinyioc/aop/ReflectiveMethodInvocation.java b/src/main/java/us/codecraft/tinyioc/aop/ReflectiveMethodInvocation.java index 78d3582..2d9281c 100644 --- a/src/main/java/us/codecraft/tinyioc/aop/ReflectiveMethodInvocation.java +++ b/src/main/java/us/codecraft/tinyioc/aop/ReflectiveMethodInvocation.java @@ -16,6 +16,7 @@ public class ReflectiveMethodInvocation implements MethodInvocation { protected Object[] arguments; + //反射方法代理类 持有对象 方法本身 方法调用的参数 public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) { this.target = target; this.method = method; diff --git a/src/main/java/us/codecraft/tinyioc/beans/AutoWired.java b/src/main/java/us/codecraft/tinyioc/beans/AutoWired.java new file mode 100644 index 0000000..d6e3f28 --- /dev/null +++ b/src/main/java/us/codecraft/tinyioc/beans/AutoWired.java @@ -0,0 +1,25 @@ +package us.codecraft.tinyioc.beans; + +/** + * @author winters + * 创建时间:13/03/2018 16:42 + * 创建原因: + **/ + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +//此处Autowired 只适用在字段注入 跟 构造注入 + +@Target({ElementType.FIELD,ElementType.CONSTRUCTOR}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface AutoWired { + + boolean required() default true; +} diff --git a/src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java b/src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java index 1695f87..b72983d 100644 --- a/src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java +++ b/src/main/java/us/codecraft/tinyioc/beans/factory/AbstractBeanFactory.java @@ -1,8 +1,10 @@ package us.codecraft.tinyioc.beans.factory; +import us.codecraft.tinyioc.beans.AutoWired; import us.codecraft.tinyioc.beans.BeanDefinition; import us.codecraft.tinyioc.beans.BeanPostProcessor; +import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -14,78 +16,115 @@ */ public abstract class AbstractBeanFactory implements BeanFactory { - private Map beanDefinitionMap = new ConcurrentHashMap(); - - private final List beanDefinitionNames = new ArrayList(); + private final List beanDefinitionNames = new ArrayList(); + private Map beanDefinitionMap = new ConcurrentHashMap(); + private List beanPostProcessors = new ArrayList(); + + @Override + public Object getBean(String name) throws Exception { + BeanDefinition beanDefinition = beanDefinitionMap.get(name); + if (beanDefinition == null) { + throw new IllegalArgumentException("No bean named " + name + " is defined"); + } + Object bean = beanDefinition.getBean(); + if (bean == null) { + // do create bean + bean = doCreateBean(beanDefinition); + // init + bean = initializeBean(bean, name); - private List beanPostProcessors = new ArrayList(); + // 初始化后获得的bean 有可能是增强实现 + // 所以在beanDefinition中更新为增强的bean - @Override - public Object getBean(String name) throws Exception { - BeanDefinition beanDefinition = beanDefinitionMap.get(name); - if (beanDefinition == null) { - throw new IllegalArgumentException("No bean named " + name + " is defined"); - } - Object bean = beanDefinition.getBean(); - if (bean == null) { - bean = doCreateBean(beanDefinition); - bean = initializeBean(bean, name); beanDefinition.setBean(bean); - } - return bean; - } + } + return bean; + } - protected Object initializeBean(Object bean, String name) throws Exception { - for (BeanPostProcessor beanPostProcessor : beanPostProcessors) { - bean = beanPostProcessor.postProcessBeforeInitialization(bean, name); - } + /* + 此方法十分重要, 在初始化bean的同时,把所有的bean + 都传入进实现了BeanPostProcessor接口的实现类中,更新对象为process增强后的bean + */ + protected Object initializeBean(Object bean, String name) throws Exception { + // 初始化的时候 调用BeanPostProcessor + + for (BeanPostProcessor beanPostProcessor : beanPostProcessors) { + //初始化之前 + bean = beanPostProcessor.postProcessBeforeInitialization(bean, name); + } + + // TODO:call initialize method + for (BeanPostProcessor beanPostProcessor : beanPostProcessors) { + //初始化之后 对bean进行增强 原始的bean 被代理bean 的引用持有 + Object preBean = bean; - // TODO:call initialize method - for (BeanPostProcessor beanPostProcessor : beanPostProcessors) { bean = beanPostProcessor.postProcessAfterInitialization(bean, name); - } + //断言 增强后的 bean 是原始bean的父类 + assert preBean.getClass().isAssignableFrom(bean.getClass()); + } + return bean; + } + + protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception { + Constructor[] constructors = beanDefinition.getBeanClass().getConstructors(); + for (int i = 0; i < constructors.length; i++) { + if (constructors[i].isAnnotationPresent(AutoWired.class) && ((AutoWired) constructors[i].getAnnotation(AutoWired.class)).required() + ) { + List objs = new ArrayList(); + for (Class clazz : constructors[i].getParameterTypes()) { + List beansForType = getBeansForType(clazz); + if (beansForType.size() == 1) { + objs.add(beansForType.get(0)); + } else { + //存在两个及其以上的候选注入bean TODO 实现Qualifier + } + } + if (objs.size() == constructors[i].getParameterCount()) { + return constructors[i].newInstance(objs.toArray()); + } else { + throw new RuntimeException("构造注入缺少指定类型的bean"); + } + } + } + return beanDefinition.getBeanClass().newInstance(); + } + + public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception { + beanDefinitionMap.put(name, beanDefinition); + beanDefinitionNames.add(name); + } + + public void preInstantiateSingletons() throws Exception { + for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext(); ) { + String beanName = (String) it.next(); + getBean(beanName); + } + } + + protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception { + Object bean = createBeanInstance(beanDefinition); + beanDefinition.setBean(bean); + applyPropertyValues(bean, beanDefinition); return bean; - } - - protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception { - return beanDefinition.getBeanClass().newInstance(); - } - - public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception { - beanDefinitionMap.put(name, beanDefinition); - beanDefinitionNames.add(name); - } - - public void preInstantiateSingletons() throws Exception { - for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) { - String beanName = (String) it.next(); - getBean(beanName); - } - } - - protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception { - Object bean = createBeanInstance(beanDefinition); - beanDefinition.setBean(bean); - applyPropertyValues(bean, beanDefinition); - return bean; - } - - protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception { - - } - - public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) throws Exception { - this.beanPostProcessors.add(beanPostProcessor); - } - - public List getBeansForType(Class type) throws Exception { - List beans = new ArrayList(); - for (String beanDefinitionName : beanDefinitionNames) { - if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) { - beans.add(getBean(beanDefinitionName)); - } - } - return beans; - } + } + + protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception { + + } + + public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) throws Exception { + this.beanPostProcessors.add(beanPostProcessor); + } + + // 所有的bean都是从beanDefinition中取出来的, + public List getBeansForType(Class type) throws Exception { + List beans = new ArrayList(); + for (String beanDefinitionName : beanDefinitionNames) { + if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) { + beans.add(getBean(beanDefinitionName)); + } + } + return beans; + } } diff --git a/src/main/java/us/codecraft/tinyioc/beans/factory/AutowireCapableBeanFactory.java b/src/main/java/us/codecraft/tinyioc/beans/factory/AutowireCapableBeanFactory.java index 740bcfb..78ae128 100644 --- a/src/main/java/us/codecraft/tinyioc/beans/factory/AutowireCapableBeanFactory.java +++ b/src/main/java/us/codecraft/tinyioc/beans/factory/AutowireCapableBeanFactory.java @@ -2,42 +2,64 @@ import us.codecraft.tinyioc.BeanReference; import us.codecraft.tinyioc.aop.BeanFactoryAware; +import us.codecraft.tinyioc.beans.AutoWired; import us.codecraft.tinyioc.beans.BeanDefinition; import us.codecraft.tinyioc.beans.PropertyValue; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.List; /** * 可自动装配内容的BeanFactory - * * @author yihua.huang@dianping.com */ public class AutowireCapableBeanFactory extends AbstractBeanFactory { - protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception { - if (bean instanceof BeanFactoryAware) { - ((BeanFactoryAware) bean).setBeanFactory(this); - } - for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) { - Object value = propertyValue.getValue(); - if (value instanceof BeanReference) { - BeanReference beanReference = (BeanReference) value; - value = getBean(beanReference.getName()); - } - - try { - Method declaredMethod = bean.getClass().getDeclaredMethod( - "set" + propertyValue.getName().substring(0, 1).toUpperCase() - + propertyValue.getName().substring(1), value.getClass()); - declaredMethod.setAccessible(true); - - declaredMethod.invoke(bean, value); - } catch (NoSuchMethodException e) { - Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName()); - declaredField.setAccessible(true); - declaredField.set(bean, value); - } - } - } + protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception { + if (bean instanceof BeanFactoryAware) { + ((BeanFactoryAware) bean).setBeanFactory(this); + } + applyPropertyValueForSetter(bean, mbd); + applyPropertyValuesForField(bean); + } + + private void applyPropertyValueForSetter(Object bean, BeanDefinition mbd) throws Exception { + for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) { + Object value = propertyValue.getValue(); + if (value instanceof BeanReference) { + BeanReference beanReference = (BeanReference) value; + value = getBean(beanReference.getName()); + } + + try { + Method declaredMethod = bean.getClass().getDeclaredMethod( + "set" + propertyValue.getName().substring(0, 1).toUpperCase() + + propertyValue.getName().substring(1), value.getClass()); + declaredMethod.setAccessible(true); + + declaredMethod.invoke(bean, value); + } catch (NoSuchMethodException e) { + Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName()); + declaredField.setAccessible(true); + declaredField.set(bean, value); + } + } + } + + private void applyPropertyValuesForField(Object bean) throws Exception { + for (Field field : bean.getClass().getDeclaredFields()) { + if (field.isAnnotationPresent(AutoWired.class) && field.getAnnotation(AutoWired.class).required()) { + field.setAccessible(true); + List beansForType = getBeansForType(field.getType()); + + //todo implement qualifier + if (beansForType.size() != 1) { + throw new RuntimeException("可选注入类型 超过1个, 或者没有可选注入类型"); + } + field.set(bean, beansForType.get(0)); + } + } + } + } diff --git a/src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java b/src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java index 0e78e7a..80a7070 100644 --- a/src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java +++ b/src/main/java/us/codecraft/tinyioc/context/AbstractApplicationContext.java @@ -1,7 +1,10 @@ package us.codecraft.tinyioc.context; +import us.codecraft.tinyioc.beans.BeanDefinition; import us.codecraft.tinyioc.beans.BeanPostProcessor; import us.codecraft.tinyioc.beans.factory.AbstractBeanFactory; +import us.codecraft.tinyioc.message.MessageHandlerHolder; +import us.codecraft.tinyioc.message.MessageHandlerInvocation; import java.util.List; @@ -9,33 +12,64 @@ * @author yihua.huang@dianping.com */ public abstract class AbstractApplicationContext implements ApplicationContext { - protected AbstractBeanFactory beanFactory; + protected AbstractBeanFactory beanFactory; - public AbstractApplicationContext(AbstractBeanFactory beanFactory) { - this.beanFactory = beanFactory; - } + private MessageHandlerHolder messageHandlerHolder = new MessageHandlerHolder(); - public void refresh() throws Exception { - loadBeanDefinitions(beanFactory); - registerBeanPostProcessors(beanFactory); - onRefresh(); - } + public AbstractApplicationContext(AbstractBeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + public void refresh() throws Exception { + loadBeanDefinitions(beanFactory); + //抽象应用上下文 向beanFactory注册beanPostProcessor + registerBeanPostProcessors(beanFactory); + //消息处理者handler 扫描所有的bean 对方法上有EventListener注解的 + beanFactory.addBeanPostProcessor(messageHandlerHolder); + //将自身注入进bean容器 + registerSelf(); + onRefresh(); + } + + private void registerSelf() throws Exception { + BeanDefinition self = new BeanDefinition(); + self.setBeanClassName(this.getClass().getName()); + self.setBeanClass(this.getClass()); + self.setBean(this); + beanFactory.registerBeanDefinition("applicationContext", self); + } - protected abstract void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception; + protected abstract void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception; - protected void registerBeanPostProcessors(AbstractBeanFactory beanFactory) throws Exception { - List beanPostProcessors = beanFactory.getBeansForType(BeanPostProcessor.class); - for (Object beanPostProcessor : beanPostProcessors) { - beanFactory.addBeanPostProcessor((BeanPostProcessor) beanPostProcessor); - } - } + //从beanFactory中 拿出所有的 BeanPostProcessor接口的实现类 + protected void registerBeanPostProcessors(AbstractBeanFactory beanFactory) throws Exception { + List beanPostProcessors = beanFactory.getBeansForType(BeanPostProcessor.class); + //全部加入到beanFactory的 beanPostProcessors 引用中去 + for (Object beanPostProcessor : beanPostProcessors) { + beanFactory.addBeanPostProcessor((BeanPostProcessor) beanPostProcessor); + } + } - protected void onRefresh() throws Exception{ + protected void onRefresh() throws Exception { beanFactory.preInstantiateSingletons(); } - @Override - public Object getBean(String name) throws Exception { - return beanFactory.getBean(name); - } + @Override + public Object getBean(String name) throws Exception { + return beanFactory.getBean(name); + } + + + @Override + public void publishEvent(Object object) { + for (MessageHandlerInvocation messageHandlerInvocation : messageHandlerHolder.getMessageHandlers()) { + if (messageHandlerInvocation.getParameterType().getType().isInstance(object)) { + try { + messageHandlerInvocation.handleMessage(object); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + } } diff --git a/src/main/java/us/codecraft/tinyioc/context/ApplicationContext.java b/src/main/java/us/codecraft/tinyioc/context/ApplicationContext.java index 7cc1902..9887fff 100644 --- a/src/main/java/us/codecraft/tinyioc/context/ApplicationContext.java +++ b/src/main/java/us/codecraft/tinyioc/context/ApplicationContext.java @@ -1,9 +1,10 @@ package us.codecraft.tinyioc.context; import us.codecraft.tinyioc.beans.factory.BeanFactory; +import us.codecraft.tinyioc.message.ApplicationEventPublisher; /** * @author yihua.huang@dianping.com */ -public interface ApplicationContext extends BeanFactory { +public interface ApplicationContext extends BeanFactory, ApplicationEventPublisher{ } diff --git a/src/main/java/us/codecraft/tinyioc/context/ClassPathXmlApplicationContext.java b/src/main/java/us/codecraft/tinyioc/context/ClassPathXmlApplicationContext.java index c2ffd76..692d78b 100644 --- a/src/main/java/us/codecraft/tinyioc/context/ClassPathXmlApplicationContext.java +++ b/src/main/java/us/codecraft/tinyioc/context/ClassPathXmlApplicationContext.java @@ -13,25 +13,26 @@ */ public class ClassPathXmlApplicationContext extends AbstractApplicationContext { - private String configLocation; - - public ClassPathXmlApplicationContext(String configLocation) throws Exception { - this(configLocation, new AutowireCapableBeanFactory()); - } - - public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception { - super(beanFactory); - this.configLocation = configLocation; - refresh(); - } - - @Override - protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception { - XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); - xmlBeanDefinitionReader.loadBeanDefinitions(configLocation); - for (Map.Entry beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) { - beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue()); - } - } + private String configLocation; + + + public ClassPathXmlApplicationContext(String configLocation) throws Exception { + this(configLocation, new AutowireCapableBeanFactory()); + } + + public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception { + super(beanFactory); + this.configLocation = configLocation; + refresh(); + } + + @Override + protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception { + XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); + xmlBeanDefinitionReader.loadBeanDefinitions(configLocation); + for (Map.Entry beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) { + beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue()); + } + } } diff --git a/src/main/java/us/codecraft/tinyioc/message/ApplicationEventPublisher.java b/src/main/java/us/codecraft/tinyioc/message/ApplicationEventPublisher.java new file mode 100644 index 0000000..22c21bb --- /dev/null +++ b/src/main/java/us/codecraft/tinyioc/message/ApplicationEventPublisher.java @@ -0,0 +1,14 @@ +package us.codecraft.tinyioc.message; + +/** + * @author winters + * 创建时间:13/03/2018 15:47 + * 创建原因: + **/ +public interface ApplicationEventPublisher { + /** + * 发布消息 + * @param object nothing + */ + void publishEvent(Object object); +} diff --git a/src/main/java/us/codecraft/tinyioc/message/EventListener.java b/src/main/java/us/codecraft/tinyioc/message/EventListener.java new file mode 100644 index 0000000..2325f9d --- /dev/null +++ b/src/main/java/us/codecraft/tinyioc/message/EventListener.java @@ -0,0 +1,20 @@ +package us.codecraft.tinyioc.message; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author winters + * 创建时间:13/03/2018 15:52 + * 创建原因: + **/ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface EventListener { +} diff --git a/src/main/java/us/codecraft/tinyioc/message/Message.java b/src/main/java/us/codecraft/tinyioc/message/Message.java new file mode 100644 index 0000000..0cbdacf --- /dev/null +++ b/src/main/java/us/codecraft/tinyioc/message/Message.java @@ -0,0 +1,16 @@ +package us.codecraft.tinyioc.message; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @author winters + * 创建时间:13/03/2018 16:22 + * 创建原因: + **/ +@Data +@AllArgsConstructor +public class Message { + + private String msg; +} diff --git a/src/main/java/us/codecraft/tinyioc/message/MessageHandlerHolder.java b/src/main/java/us/codecraft/tinyioc/message/MessageHandlerHolder.java new file mode 100644 index 0000000..c702ea7 --- /dev/null +++ b/src/main/java/us/codecraft/tinyioc/message/MessageHandlerHolder.java @@ -0,0 +1,43 @@ +package us.codecraft.tinyioc.message; + +import us.codecraft.tinyioc.beans.BeanPostProcessor; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * @author winters + * 创建时间:13/03/2018 15:51 + * 创建原因: + **/ +//实现了 beanPostProcessor接口 +public class MessageHandlerHolder implements BeanPostProcessor { + + private List messageHandlers = new ArrayList<>(); + + public List getMessageHandlers() { + return messageHandlers; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception { + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { + for (Method method : bean.getClass().getMethods()) { + if (method.isAnnotationPresent(EventListener.class)) { + if (method.getParameters().length == 1) { + MessageHandlerInvocation messageHandlerInvocation = new MessageHandlerInvocation( + method, + method.getParameters()[0], bean); + messageHandlers.add(messageHandlerInvocation); + } + } + } + return bean; + } + +} diff --git a/src/main/java/us/codecraft/tinyioc/message/MessageHandlerInvocation.java b/src/main/java/us/codecraft/tinyioc/message/MessageHandlerInvocation.java new file mode 100644 index 0000000..21aa273 --- /dev/null +++ b/src/main/java/us/codecraft/tinyioc/message/MessageHandlerInvocation.java @@ -0,0 +1,33 @@ +package us.codecraft.tinyioc.message; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +/** + * @author winters + * 创建时间:13/03/2018 15:57 + * 创建原因: + **/ +public class MessageHandlerInvocation { + + private Method method; + + public Parameter getParameterType() { + return parameterType; + } + + private Parameter parameterType; + + private Object target; + + public MessageHandlerInvocation(Method method, Parameter parameter, Object target) { + this.method = method; + this.parameterType = parameter; + this.target = target; + } + + public void handleMessage(Object object) throws InvocationTargetException, IllegalAccessException { + method.invoke(target, object); + } +} diff --git a/src/test/java/us/codecraft/tinyioc/BeanFactoryTest.java b/src/test/java/us/codecraft/tinyioc/BeanFactoryTest.java index dfae7c5..8e701b7 100644 --- a/src/test/java/us/codecraft/tinyioc/BeanFactoryTest.java +++ b/src/test/java/us/codecraft/tinyioc/BeanFactoryTest.java @@ -1,6 +1,5 @@ package us.codecraft.tinyioc; -import java.util.Map; import org.junit.Test; import us.codecraft.tinyioc.beans.BeanDefinition; import us.codecraft.tinyioc.beans.factory.AbstractBeanFactory; @@ -8,6 +7,8 @@ import us.codecraft.tinyioc.beans.io.ResourceLoader; import us.codecraft.tinyioc.beans.xml.XmlBeanDefinitionReader; +import java.util.Map; + /** * @author yihua.huang@dianping.com */ diff --git a/src/test/java/us/codecraft/tinyioc/HelloWorldServiceImpl.java b/src/test/java/us/codecraft/tinyioc/HelloWorldServiceImpl.java index 0958882..adfa553 100644 --- a/src/test/java/us/codecraft/tinyioc/HelloWorldServiceImpl.java +++ b/src/test/java/us/codecraft/tinyioc/HelloWorldServiceImpl.java @@ -1,25 +1,39 @@ package us.codecraft.tinyioc; +import lombok.Data; +import lombok.NoArgsConstructor; +import us.codecraft.tinyioc.beans.AutoWired; +import us.codecraft.tinyioc.message.ApplicationEventPublisher; +import us.codecraft.tinyioc.message.EventListener; +import us.codecraft.tinyioc.message.Message; + /** * @author yihua.huang@dianping.com */ +@Data +@NoArgsConstructor public class HelloWorldServiceImpl implements HelloWorldService { private String text; - private OutputService outputService; - @Override - public void helloWorld(){ - outputService.output(text); - } + @AutoWired(required = false) + private ApplicationEventPublisher applicationEventPublisher; - public void setText(String text) { - this.text = text; + @AutoWired(required = false) + public HelloWorldServiceImpl(OutputService outputService, ApplicationEventPublisher applicationEventPublisher) { + this.outputService = outputService; + this.applicationEventPublisher = applicationEventPublisher; } - public void setOutputService(OutputService outputService) { - this.outputService = outputService; + @Override + public void helloWorld() { + outputService.output(text); } + @EventListener + public void handleMessage(String msg) { + System.out.println("Handle type String's message is:" + msg); + applicationEventPublisher.publishEvent(new Message("through autowired publisher publish this message")); + } } diff --git a/src/test/java/us/codecraft/tinyioc/OutputServiceImpl.java b/src/test/java/us/codecraft/tinyioc/OutputServiceImpl.java index a840fe8..eb1d718 100644 --- a/src/test/java/us/codecraft/tinyioc/OutputServiceImpl.java +++ b/src/test/java/us/codecraft/tinyioc/OutputServiceImpl.java @@ -1,13 +1,25 @@ package us.codecraft.tinyioc; +import lombok.Data; +import us.codecraft.tinyioc.message.EventListener; +import us.codecraft.tinyioc.message.Message; + /** * @author yihua.huang@dianping.com */ +@Data public class OutputServiceImpl implements OutputService { + HelloWorldService helloWorldService; + @Override public void output(String text){ System.out.println(text); } + @EventListener + public void handleMessage(Message message){ + System.out.println("Handle message'type is Message msg is: " + message.getMsg()); + } + } diff --git a/src/test/java/us/codecraft/tinyioc/aop/TimerInterceptor.java b/src/test/java/us/codecraft/tinyioc/aop/TimerInterceptor.java index 4547c51..eee92af 100644 --- a/src/test/java/us/codecraft/tinyioc/aop/TimerInterceptor.java +++ b/src/test/java/us/codecraft/tinyioc/aop/TimerInterceptor.java @@ -8,11 +8,17 @@ */ public class TimerInterceptor implements MethodInterceptor { + //代理回调 @Override public Object invoke(MethodInvocation invocation) throws Throwable { long time = System.nanoTime(); System.out.println("Invocation of Method " + invocation.getMethod().getName() + " start!"); + //执行真正的bean方法前 + + //执行bean原始方法 Object proceed = invocation.proceed(); + + //执行真正的bean方法后 System.out.println("Invocation of Method " + invocation.getMethod().getName() + " end! takes " + (System.nanoTime() - time) + " nanoseconds."); return proceed; diff --git a/src/test/java/us/codecraft/tinyioc/context/ApplicationContextTest.java b/src/test/java/us/codecraft/tinyioc/context/ApplicationContextTest.java index 5d57588..93afb68 100644 --- a/src/test/java/us/codecraft/tinyioc/context/ApplicationContextTest.java +++ b/src/test/java/us/codecraft/tinyioc/context/ApplicationContextTest.java @@ -2,6 +2,7 @@ import org.junit.Test; import us.codecraft.tinyioc.HelloWorldService; +import us.codecraft.tinyioc.message.Message; /** * @author yihua.huang@dianping.com @@ -19,6 +20,8 @@ public void test() throws Exception { public void testPostBeanProcessor() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc-postbeanprocessor.xml"); HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService"); + applicationContext.publishEvent("test"); + applicationContext.publishEvent(new Message("test")); helloWorldService.helloWorld(); } }