├── .gitignore ├── LICENSE.txt ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── titizz │ └── simulation │ └── toyspring │ ├── aop │ ├── AbstractAopProxy.java │ ├── AdvisedSupport.java │ ├── Advisor.java │ ├── AopProxy.java │ ├── AspectJAwareAdvisorAutoProxyCreator.java │ ├── AspectJExpressionPointcut.java │ ├── AspectJExpressionPointcutAdvisor.java │ ├── ClassFilter.java │ ├── JdkDynamicAopProxy.java │ ├── MethodMatcher.java │ ├── Pointcut.java │ ├── PointcutAdvisor.java │ ├── ProxyFactory.java │ ├── ReflectiveMethodInvocation.java │ └── TargetSource.java │ ├── ioc │ ├── BeanDefinition.java │ ├── BeanDefinitionReader.java │ ├── BeanPostProcessor.java │ ├── BeanReference.java │ ├── PropertyValue.java │ ├── PropertyValues.java │ ├── factory │ │ ├── BeanFactory.java │ │ └── BeanFactoryAware.java │ └── xml │ │ ├── XmlBeanDefinitionReader.java │ │ └── XmlBeanFactory.java │ └── simple │ ├── Advice.java │ ├── BeforeAdvice.java │ ├── MethodInvocation.java │ ├── SimpleAOP.java │ └── SimpleIOC.java └── test ├── java └── com │ └── titizz │ └── simulation │ └── toyspring │ ├── Car.java │ ├── HelloService.java │ ├── HelloServiceImpl.java │ ├── Wheel.java │ ├── aop │ ├── AspectJExpressionPointcutTest.java │ ├── JdkDynamicAopProxyTest.java │ └── LogInterceptor.java │ ├── ioc │ └── XmlBeanFactoryTest.java │ └── simple │ ├── SimpleAOPTest.java │ └── SimpleIOCTest.java └── resources ├── toy-spring-ioc.xml └── toy-spring.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | *.rdb 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | short-url.iml 27 | *.iml 28 | .idea 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "{}" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright 2017 code4wt 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # toy-spring 2 | 仿照 tiny-spring 项目编写的的一个玩具级 spring 项目,实现了简单的 IOC 和 AOP 功能。 3 | 4 | 本项目包含了两个不同版本的 IOC 和 AOP 实现,相关源码包结构如下: 5 | 6 | * simple,包含了简单的 IOC 和 AOP 实现代码 7 | * ioc,包含了较为复杂的 IOC 实现代码 8 | * aop,包含了较为复杂的 AOP 实现代码 9 | 10 | 项目详细介绍请移步到本人的博客 -> [仿照 Spring 实现简单的 IOC 和 AOP](https://segmentfault.com/a/1190000010745705) 11 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.titizz.simulation 8 | toy-spring 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | junit 14 | junit 15 | 4.12 16 | 17 | 18 | aopalliance 19 | aopalliance 20 | 1.0 21 | 22 | 23 | org.aspectj 24 | aspectjweaver 25 | 1.8.10 26 | 27 | 28 | cglib 29 | cglib-nodep 30 | 3.2.5 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-compiler-plugin 39 | 40 | 1.8 41 | 1.8 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/AbstractAopProxy.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | /** 4 | * Created by code4wt on 17/8/16. 5 | */ 6 | public abstract class AbstractAopProxy implements AopProxy { 7 | 8 | protected AdvisedSupport advised; 9 | 10 | public AbstractAopProxy(AdvisedSupport advised) { 11 | this.advised = advised; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/AdvisedSupport.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import org.aopalliance.intercept.MethodInterceptor; 4 | 5 | /** 6 | * Created by code4wt on 17/8/16. 7 | */ 8 | public class AdvisedSupport { 9 | 10 | private TargetSource targetSource; 11 | 12 | private MethodInterceptor methodInterceptor; 13 | 14 | private MethodMatcher methodMatcher; 15 | 16 | public TargetSource getTargetSource() { 17 | return targetSource; 18 | } 19 | 20 | public void setTargetSource(TargetSource targetSource) { 21 | this.targetSource = targetSource; 22 | } 23 | 24 | public MethodInterceptor getMethodInterceptor() { 25 | return methodInterceptor; 26 | } 27 | 28 | public void setMethodInterceptor(MethodInterceptor methodInterceptor) { 29 | this.methodInterceptor = methodInterceptor; 30 | } 31 | 32 | public MethodMatcher getMethodMatcher() { 33 | return methodMatcher; 34 | } 35 | 36 | public void setMethodMatcher(MethodMatcher methodMatcher) { 37 | this.methodMatcher = methodMatcher; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/Advisor.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import org.aopalliance.aop.Advice; 4 | 5 | /** 6 | * Created by code4wt on 17/8/16. 7 | */ 8 | public interface Advisor { 9 | 10 | Advice getAdvice(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/AopProxy.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | /** 4 | * Created by code4wt on 17/8/16. 5 | */ 6 | public interface AopProxy { 7 | 8 | Object getProxy(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/AspectJAwareAdvisorAutoProxyCreator.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import com.titizz.simulation.toyspring.ioc.BeanPostProcessor; 4 | import com.titizz.simulation.toyspring.ioc.factory.BeanFactory; 5 | import com.titizz.simulation.toyspring.ioc.factory.BeanFactoryAware; 6 | import com.titizz.simulation.toyspring.ioc.xml.XmlBeanFactory; 7 | import org.aopalliance.intercept.MethodInterceptor; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Created by code4wt on 17/8/16. 13 | */ 14 | public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware { 15 | 16 | private XmlBeanFactory xmlBeanFactory; 17 | 18 | @Override 19 | public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception { 20 | return bean; 21 | } 22 | 23 | @Override 24 | public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { 25 | /* 这里两个 if 判断很有必要,如果删除将会使程序进入死循环状态, 26 | * 最终导致 StackOverflowError 错误发生 27 | */ 28 | if (bean instanceof AspectJExpressionPointcutAdvisor) { 29 | return bean; 30 | } 31 | if (bean instanceof MethodInterceptor) { 32 | return bean; 33 | } 34 | 35 | // 1. 从 BeanFactory 查找 AspectJExpressionPointcutAdvisor 类型的对象 36 | List advisors = 37 | xmlBeanFactory.getBeansForType(AspectJExpressionPointcutAdvisor.class); 38 | for (AspectJExpressionPointcutAdvisor advisor : advisors) { 39 | 40 | // 2. 使用 Pointcut 对象匹配当前 bean 对象 41 | if (advisor.getPointcut().getClassFilter().matchers(bean.getClass())) { 42 | ProxyFactory advisedSupport = new ProxyFactory(); 43 | advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); 44 | advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher()); 45 | 46 | TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces()); 47 | advisedSupport.setTargetSource(targetSource); 48 | 49 | // 3. 生成代理对象,并返回 50 | return advisedSupport.getProxy(); 51 | } 52 | } 53 | 54 | // 2. 匹配失败,返回 bean 55 | return bean; 56 | } 57 | 58 | @Override 59 | public void setBeanFactory(BeanFactory beanFactory) throws Exception { 60 | xmlBeanFactory = (XmlBeanFactory) beanFactory; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/AspectJExpressionPointcut.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import org.aspectj.weaver.tools.PointcutExpression; 4 | import org.aspectj.weaver.tools.PointcutParser; 5 | import org.aspectj.weaver.tools.PointcutPrimitive; 6 | import org.aspectj.weaver.tools.ShadowMatch; 7 | 8 | import java.lang.reflect.Method; 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | /** 13 | * Created by code4wt on 17/8/16. 14 | */ 15 | public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher { 16 | 17 | private PointcutParser pointcutParser; 18 | 19 | private String expression; 20 | 21 | private PointcutExpression pointcutExpression; 22 | 23 | private static final Set DEFAULT_SUPPORTED_PRIMITIVES = new HashSet<>(); 24 | 25 | static { 26 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION); 27 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS); 28 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE); 29 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS); 30 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET); 31 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN); 32 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION); 33 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN); 34 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS); 35 | DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET); 36 | } 37 | 38 | public AspectJExpressionPointcut() { 39 | this(DEFAULT_SUPPORTED_PRIMITIVES); 40 | } 41 | 42 | public AspectJExpressionPointcut(Set supportedPrimitives) { 43 | pointcutParser = PointcutParser 44 | .getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives); 45 | } 46 | 47 | /** 48 | * 使用 AspectJ Expression 匹配类 49 | * @param targetClass 50 | * @return成功匹配返回 true,否则返回 false 51 | */ 52 | @Override 53 | public Boolean matchers(Class targetClass) { 54 | checkReadyToMatche(); 55 | return pointcutExpression.couldMatchJoinPointsInType(targetClass); 56 | } 57 | 58 | /** 59 | * 使用 AspectJ Expression 匹配方法 60 | * @param method 61 | * @param targetClass 62 | * @return 成功匹配返回 true,否则返回 false 63 | */ 64 | @Override 65 | public Boolean matchers(Method method, Class targetClass) { 66 | checkReadyToMatche(); 67 | ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method); 68 | 69 | // Special handling for this, target, @this, @target, @annotation 70 | // in Spring - we can optimize since we know we have exactly this class, 71 | // and there will never be matching subclass at runtime. 72 | // https://github.com/spring-projects/spring-framework/blob/master/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java 73 | if (shadowMatch.alwaysMatches()) { 74 | return true; 75 | } 76 | else if (shadowMatch.neverMatches()) { 77 | return false; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | private void checkReadyToMatche() { 84 | if (getExpression() == null) { 85 | throw new IllegalStateException("Must set property 'expression' before attempting to match"); 86 | } 87 | if (pointcutExpression == null) { 88 | pointcutExpression = pointcutParser.parsePointcutExpression(expression); 89 | } 90 | } 91 | 92 | @Override 93 | public ClassFilter getClassFilter() { 94 | return this; 95 | } 96 | 97 | @Override 98 | public MethodMatcher getMethodMatcher() { 99 | return this; 100 | } 101 | 102 | public void setExpression(String expression) { 103 | this.expression = expression; 104 | } 105 | 106 | public String getExpression() { 107 | return expression; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/AspectJExpressionPointcutAdvisor.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import org.aopalliance.aop.Advice; 4 | 5 | /** 6 | * Created by code4wt on 17/8/16. 7 | */ 8 | public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor { 9 | 10 | private AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); 11 | 12 | private Advice advice; 13 | 14 | public void setExpression(String expression) { 15 | pointcut.setExpression(expression); 16 | } 17 | 18 | public void setAdvice(Advice advice) { 19 | this.advice = advice; 20 | } 21 | 22 | @Override 23 | public Pointcut getPointcut() { 24 | return pointcut; 25 | } 26 | 27 | @Override 28 | public Advice getAdvice() { 29 | return advice; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/ClassFilter.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | /** 4 | * Created by code4wt on 17/8/16. 5 | */ 6 | public interface ClassFilter { 7 | 8 | Boolean matchers(Class beanClass) throws Exception; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/JdkDynamicAopProxy.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import org.aopalliance.intercept.MethodInterceptor; 4 | 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | import java.lang.reflect.Proxy; 8 | 9 | /** 10 | * 基于 JDK 动态代理的代理对象生成器 11 | * Created by code4wt on 17/8/16. 12 | */ 13 | final public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler { 14 | 15 | public JdkDynamicAopProxy(AdvisedSupport advised) { 16 | super(advised); 17 | } 18 | 19 | /** 20 | * 为目标 bean 生成代理对象 21 | * 22 | * @return bean 的代理对象 23 | */ 24 | @Override 25 | public Object getProxy() { 26 | return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getInterfaces(), this); 27 | } 28 | 29 | /** 30 | * InvocationHandler 接口中的 invoke 方法具体实现,封装了具体的代理逻辑 31 | * 32 | * @param proxy 33 | * @param method 34 | * @param args 35 | * @return 代理方法或原方法的返回值 36 | * @throws Throwable 37 | */ 38 | @Override 39 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 40 | MethodMatcher methodMatcher = advised.getMethodMatcher(); 41 | 42 | // 使用方法匹配器 methodMatcher 测试 bean 中原始方法 method 是否符合匹配规则 43 | if (methodMatcher != null && methodMatcher.matchers(method, advised.getTargetSource().getTargetClass())) { 44 | 45 | // 获取 Advice。MethodInterceptor 的父接口继承了 Advice 46 | MethodInterceptor methodInterceptor = advised.getMethodInterceptor(); 47 | 48 | // 将 bean 的原始 method 封装成 MethodInvocation 实现类对象, 49 | // 将生成的对象传给 Adivce 实现类对象,执行通知逻辑 50 | return methodInterceptor.invoke( 51 | new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args)); 52 | } else { 53 | // 当前 method 不符合匹配规则,直接调用 bean 中的原始 method 54 | return method.invoke(advised.getTargetSource().getTarget(), args); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/MethodMatcher.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * Created by code4wt on 17/8/16. 7 | */ 8 | public interface MethodMatcher { 9 | 10 | Boolean matchers(Method method, Class beanClass); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/Pointcut.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | /** 4 | * Created by code4wt on 17/8/16. 5 | */ 6 | public interface Pointcut { 7 | 8 | ClassFilter getClassFilter(); 9 | 10 | MethodMatcher getMethodMatcher(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/PointcutAdvisor.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | /** 4 | * @author yihua.huang@dianping.com 5 | */ 6 | public interface PointcutAdvisor extends Advisor { 7 | 8 | Pointcut getPointcut(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/ProxyFactory.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | /** 4 | * Created by code4wt on 17/8/17. 5 | */ 6 | public class ProxyFactory extends AdvisedSupport implements AopProxy { 7 | 8 | @Override 9 | public Object getProxy() { 10 | return createAopProxy().getProxy(); 11 | } 12 | 13 | private AopProxy createAopProxy() { 14 | return new JdkDynamicAopProxy(this); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/ReflectiveMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import org.aopalliance.intercept.MethodInvocation; 4 | 5 | import java.lang.reflect.AccessibleObject; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * Created by code4wt on 17/8/16. 10 | */ 11 | public class ReflectiveMethodInvocation implements MethodInvocation { 12 | 13 | protected Object target; 14 | 15 | protected Method method; 16 | 17 | protected Object[] arguments; 18 | 19 | public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) { 20 | this.target = target; 21 | this.method = method; 22 | this.arguments = arguments; 23 | } 24 | 25 | @Override 26 | public Object proceed() throws Throwable { 27 | return method.invoke(target, arguments); 28 | } 29 | 30 | @Override 31 | public Method getMethod() { 32 | return method; 33 | } 34 | 35 | @Override 36 | public Object[] getArguments() { 37 | return arguments; 38 | } 39 | 40 | @Override 41 | public Object getThis() { 42 | return target; 43 | } 44 | 45 | @Override 46 | public AccessibleObject getStaticPart() { 47 | return method; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/aop/TargetSource.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | public class TargetSource { 4 | 5 | private Class targetClass; 6 | 7 | private Class[] interfaces; 8 | 9 | private Object target; 10 | 11 | public TargetSource(Object target, Class targetClass, Class... interfaces) { 12 | this.target = target; 13 | this.targetClass = targetClass; 14 | this.interfaces = interfaces; 15 | } 16 | 17 | public Class getTargetClass() { 18 | return targetClass; 19 | } 20 | 21 | public Object getTarget() { 22 | return target; 23 | } 24 | 25 | public Class[] getInterfaces() { 26 | return interfaces; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/BeanDefinition.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc; 2 | 3 | /** 4 | * Created by code4wt on 17/8/3. 5 | */ 6 | public class BeanDefinition { 7 | 8 | private Object bean; 9 | 10 | private Class beanClass; 11 | 12 | private String beanClassName; 13 | 14 | private PropertyValues propertyValues = new PropertyValues(); 15 | 16 | public BeanDefinition() { 17 | } 18 | 19 | public void setBean(Object bean) { 20 | this.bean = bean; 21 | } 22 | 23 | public Class getBeanClass() { 24 | return beanClass; 25 | } 26 | 27 | public void setBeanClass(Class beanClass) { 28 | this.beanClass = beanClass; 29 | } 30 | 31 | public String getBeanClassName() { 32 | return beanClassName; 33 | } 34 | 35 | public void setBeanClassName(String beanClassName) { 36 | this.beanClassName = beanClassName; 37 | try { 38 | this.beanClass = Class.forName(beanClassName); 39 | } catch (ClassNotFoundException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | public Object getBean() { 45 | return bean; 46 | } 47 | 48 | public PropertyValues getPropertyValues() { 49 | return propertyValues; 50 | } 51 | 52 | public void setPropertyValues(PropertyValues propertyValues) { 53 | this.propertyValues = propertyValues; 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/BeanDefinitionReader.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc; 2 | 3 | import java.io.FileNotFoundException; 4 | 5 | /** 6 | * Created by code4wt on 17/8/2. 7 | */ 8 | public interface BeanDefinitionReader { 9 | 10 | void loadBeanDefinitions(String location) throws FileNotFoundException, Exception; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/BeanPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc; 2 | 3 | /** 4 | * Created by code4wt on 17/8/3. 5 | */ 6 | public interface BeanPostProcessor { 7 | 8 | Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception; 9 | 10 | Object postProcessAfterInitialization(Object bean, String beanName) throws Exception; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/BeanReference.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc; 2 | 3 | /** 4 | * Created by code4wt on 17/8/15. 5 | */ 6 | public class BeanReference { 7 | 8 | private String name; 9 | 10 | private Object bean; 11 | 12 | public BeanReference(String name) { 13 | this.name = name; 14 | } 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public Object getBean() { 25 | return bean; 26 | } 27 | 28 | public void setBean(Object bean) { 29 | this.bean = bean; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/PropertyValue.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc; 2 | 3 | /** 4 | * Created by code4wt on 17/8/3. 5 | */ 6 | public class PropertyValue { 7 | 8 | private final String name; 9 | 10 | private final Object value; 11 | 12 | public PropertyValue(String name, Object value) { 13 | this.name = name; 14 | this.value = value; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public Object getValue() { 22 | return value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/PropertyValues.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by code4wt on 17/8/3. 8 | */ 9 | public class PropertyValues { 10 | 11 | private final List propertyValueList = new ArrayList(); 12 | 13 | public void addPropertyValue(PropertyValue pv) { 14 | // 在这里可以对参数值 pv 做一些处理,如果直接使用 List,则就不行了 15 | this.propertyValueList.add(pv); 16 | } 17 | 18 | public List getPropertyValues() { 19 | return this.propertyValueList; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/factory/BeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc.factory; 2 | 3 | /** 4 | * Created by code4wt on 17/8/2. 5 | */ 6 | public interface BeanFactory { 7 | Object getBean(String beanId) throws Exception; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/factory/BeanFactoryAware.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc.factory; 2 | 3 | /** 4 | * Created by code4wt on 17/8/16. 5 | */ 6 | public interface BeanFactoryAware { 7 | 8 | void setBeanFactory(BeanFactory beanFactory) throws Exception; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/xml/XmlBeanDefinitionReader.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc.xml; 2 | 3 | import com.titizz.simulation.toyspring.ioc.BeanDefinition; 4 | import com.titizz.simulation.toyspring.ioc.BeanDefinitionReader; 5 | import com.titizz.simulation.toyspring.ioc.BeanReference; 6 | import com.titizz.simulation.toyspring.ioc.PropertyValue; 7 | import org.w3c.dom.Document; 8 | import org.w3c.dom.Element; 9 | import org.w3c.dom.Node; 10 | import org.w3c.dom.NodeList; 11 | 12 | import javax.xml.parsers.DocumentBuilder; 13 | import javax.xml.parsers.DocumentBuilderFactory; 14 | import java.io.FileInputStream; 15 | import java.io.InputStream; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | /** 20 | * Created by code4wt on 17/8/2. 21 | */ 22 | public class XmlBeanDefinitionReader implements BeanDefinitionReader { 23 | 24 | private Map registry; 25 | 26 | public XmlBeanDefinitionReader() { 27 | registry = new HashMap<>(); 28 | } 29 | 30 | @Override 31 | public void loadBeanDefinitions(String location) throws Exception { 32 | InputStream inputStream = new FileInputStream(location); 33 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 34 | DocumentBuilder docBuilder = factory.newDocumentBuilder(); 35 | Document doc = docBuilder.parse(inputStream); 36 | Element root = doc.getDocumentElement(); 37 | parseBeanDefinitions(root); 38 | } 39 | 40 | private void parseBeanDefinitions(Element root) throws Exception { 41 | NodeList nodes = root.getChildNodes(); 42 | for (int i = 0; i < nodes.getLength(); i++) { 43 | Node node = nodes.item(i); 44 | if (node instanceof Element) { 45 | Element ele = (Element) node; 46 | parseBeanDefinition(ele); 47 | } 48 | } 49 | } 50 | 51 | private void parseBeanDefinition(Element ele) throws Exception { 52 | String name = ele.getAttribute("id"); 53 | String className = ele.getAttribute("class"); 54 | BeanDefinition beanDefinition = new BeanDefinition(); 55 | beanDefinition.setBeanClassName(className); 56 | processProperty(ele, beanDefinition); 57 | registry.put(name, beanDefinition); 58 | } 59 | 60 | private void processProperty(Element ele, BeanDefinition beanDefinition) { 61 | NodeList propertyNodes = ele.getElementsByTagName("property"); 62 | for (int i = 0; i < propertyNodes.getLength(); i++) { 63 | Node propertyNode = propertyNodes.item(i); 64 | if (propertyNode instanceof Element) { 65 | Element propertyElement = (Element) propertyNode; 66 | String name = propertyElement.getAttribute("name"); 67 | String value = propertyElement.getAttribute("value"); 68 | if (value != null && value.length() > 0) { 69 | beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value)); 70 | } else { 71 | String ref = propertyElement.getAttribute("ref"); 72 | if (ref == null || ref.length() == 0) { 73 | throw new IllegalArgumentException("ref config error"); 74 | } 75 | BeanReference beanReference = new BeanReference(ref); 76 | beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference)); 77 | } 78 | } 79 | } 80 | } 81 | 82 | public Map getRegistry() { 83 | return registry; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/ioc/xml/XmlBeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc.xml; 2 | 3 | import com.titizz.simulation.toyspring.ioc.BeanDefinition; 4 | import com.titizz.simulation.toyspring.ioc.BeanPostProcessor; 5 | import com.titizz.simulation.toyspring.ioc.BeanReference; 6 | import com.titizz.simulation.toyspring.ioc.PropertyValue; 7 | import com.titizz.simulation.toyspring.ioc.factory.BeanFactory; 8 | import com.titizz.simulation.toyspring.ioc.factory.BeanFactoryAware; 9 | 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.Method; 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * Created by code4wt on 17/8/2. 19 | */ 20 | public class XmlBeanFactory implements BeanFactory { 21 | 22 | private Map beanDefinitionMap = new HashMap<>(); 23 | 24 | private List beanDefinitionNames = new ArrayList<>(); 25 | 26 | private List beanPostProcessors = new ArrayList(); 27 | 28 | private XmlBeanDefinitionReader beanDefinitionReader; 29 | 30 | 31 | public XmlBeanFactory(String location) throws Exception { 32 | beanDefinitionReader = new XmlBeanDefinitionReader(); 33 | loadBeanDefinitions(location); 34 | } 35 | 36 | public Object getBean(String name) throws Exception { 37 | BeanDefinition beanDefinition = beanDefinitionMap.get(name); 38 | if (beanDefinition == null) { 39 | throw new IllegalArgumentException("no this bean with name " + name); 40 | } 41 | 42 | Object bean = beanDefinition.getBean(); 43 | if (bean == null) { 44 | bean = createBean(beanDefinition); 45 | bean = initializeBean(bean, name); 46 | beanDefinition.setBean(bean); 47 | } 48 | 49 | return bean; 50 | } 51 | 52 | private Object createBean(BeanDefinition bd) throws Exception { 53 | Object bean = bd.getBeanClass().newInstance(); 54 | applyPropertyValues(bean, bd); 55 | 56 | return bean; 57 | } 58 | 59 | private void applyPropertyValues(Object bean, BeanDefinition bd) throws Exception { 60 | if (bean instanceof BeanFactoryAware) { 61 | ((BeanFactoryAware) bean).setBeanFactory(this); 62 | } 63 | for (PropertyValue propertyValue : bd.getPropertyValues().getPropertyValues()) { 64 | Object value = propertyValue.getValue(); 65 | if (value instanceof BeanReference) { 66 | BeanReference beanReference = (BeanReference) value; 67 | value = getBean(beanReference.getName()); 68 | } 69 | 70 | try { 71 | Method declaredMethod = bean.getClass().getDeclaredMethod( 72 | "set" + propertyValue.getName().substring(0, 1).toUpperCase() 73 | + propertyValue.getName().substring(1), value.getClass()); 74 | declaredMethod.setAccessible(true); 75 | 76 | declaredMethod.invoke(bean, value); 77 | } catch (NoSuchMethodException e) { 78 | Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName()); 79 | declaredField.setAccessible(true); 80 | declaredField.set(bean, value); 81 | } 82 | } 83 | } 84 | 85 | private Object initializeBean(Object bean, String name) throws Exception { 86 | for (BeanPostProcessor beanPostProcessor : beanPostProcessors) { 87 | bean = beanPostProcessor.postProcessBeforeInitialization(bean, name); 88 | } 89 | 90 | for (BeanPostProcessor beanPostProcessor : beanPostProcessors) { 91 | bean = beanPostProcessor.postProcessAfterInitialization(bean, name); 92 | } 93 | 94 | return bean; 95 | } 96 | 97 | private void loadBeanDefinitions(String location) throws Exception { 98 | beanDefinitionReader.loadBeanDefinitions(location); 99 | registerBeanDefinition(); 100 | registerBeanPostProcessor(); 101 | } 102 | 103 | private void registerBeanDefinition() { 104 | for (Map.Entry entry : beanDefinitionReader.getRegistry().entrySet()) { 105 | String name = entry.getKey(); 106 | BeanDefinition beanDefinition = entry.getValue(); 107 | beanDefinitionMap.put(name, beanDefinition); 108 | beanDefinitionNames.add(name); 109 | } 110 | } 111 | 112 | public void registerBeanPostProcessor() throws Exception { 113 | List beans = getBeansForType(BeanPostProcessor.class); 114 | for (Object bean : beans) { 115 | addBeanPostProcessor((BeanPostProcessor) bean); 116 | } 117 | } 118 | 119 | public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) { 120 | beanPostProcessors.add(beanPostProcessor); 121 | } 122 | 123 | public List getBeansForType(Class type) throws Exception { 124 | List beans = new ArrayList<>(); 125 | for (String beanDefinitionName : beanDefinitionNames) { 126 | if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) { 127 | beans.add(getBean(beanDefinitionName)); 128 | } 129 | } 130 | return beans; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/simple/Advice.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.simple; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | 5 | /** 6 | * Created by code4wt on 17/8/19. 7 | */ 8 | public interface Advice extends InvocationHandler { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/simple/BeforeAdvice.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.simple; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * Created by code4wt on 17/8/19. 7 | */ 8 | public class BeforeAdvice implements Advice { 9 | 10 | private Object bean; 11 | 12 | private MethodInvocation methodInvocation; 13 | 14 | public BeforeAdvice(Object bean, MethodInvocation methodInvocation) { 15 | this.bean = bean; 16 | this.methodInvocation = methodInvocation; 17 | } 18 | 19 | @Override 20 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 21 | methodInvocation.invoke(); 22 | return method.invoke(bean, args); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/simple/MethodInvocation.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.simple; 2 | 3 | /** 4 | * Created by code4wt on 17/8/19. 5 | */ 6 | public interface MethodInvocation { 7 | 8 | void invoke(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/simple/SimpleAOP.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.simple; 2 | 3 | import java.lang.reflect.Proxy; 4 | 5 | /** 6 | * Created by code4wt on 17/8/18. 7 | */ 8 | public class SimpleAOP { 9 | 10 | public static Object getProxy(Object bean, Advice advice) { 11 | return Proxy.newProxyInstance(SimpleAOP.class.getClassLoader(), bean.getClass().getInterfaces(), advice); 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/com/titizz/simulation/toyspring/simple/SimpleIOC.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.simple; 2 | 3 | import org.w3c.dom.Document; 4 | import org.w3c.dom.Element; 5 | import org.w3c.dom.Node; 6 | import org.w3c.dom.NodeList; 7 | 8 | import javax.xml.parsers.DocumentBuilder; 9 | import javax.xml.parsers.DocumentBuilderFactory; 10 | import java.io.FileInputStream; 11 | import java.io.InputStream; 12 | import java.lang.reflect.Field; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * Created by code4wt on 17/8/18. 18 | */ 19 | public class SimpleIOC { 20 | 21 | private Map beanMap = new HashMap<>(); 22 | 23 | public SimpleIOC(String location) throws Exception { 24 | loadBeans(location); 25 | } 26 | 27 | public Object getBean(String name) { 28 | Object bean = beanMap.get(name); 29 | if (bean == null) { 30 | throw new IllegalArgumentException("there is no bean with name " + name); 31 | } 32 | 33 | return bean; 34 | } 35 | 36 | private void loadBeans(String location) throws Exception { 37 | // 加载 xml 配置文件 38 | InputStream inputStream = new FileInputStream(location); 39 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 40 | DocumentBuilder docBuilder = factory.newDocumentBuilder(); 41 | Document doc = docBuilder.parse(inputStream); 42 | Element root = doc.getDocumentElement(); 43 | NodeList nodes = root.getChildNodes(); 44 | 45 | // 遍历 标签 46 | for (int i = 0; i < nodes.getLength(); i++) { 47 | Node node = nodes.item(i); 48 | if (node instanceof Element) { 49 | Element ele = (Element) node; 50 | String id = ele.getAttribute("id"); 51 | String className = ele.getAttribute("class"); 52 | Class beanClass = null; 53 | try { 54 | beanClass = Class.forName(className); 55 | } catch (ClassNotFoundException e) { 56 | e.printStackTrace(); 57 | return; 58 | } 59 | 60 | Object bean = beanClass.newInstance(); 61 | 62 | // 处理 bean property 属性 63 | NodeList propertyNodes = ele.getElementsByTagName("property"); 64 | for (int j = 0; j < propertyNodes.getLength(); j++) { 65 | Node propertyNode = propertyNodes.item(j); 66 | if (propertyNode instanceof Element) { 67 | Element propertyElement = (Element) propertyNode; 68 | String name = propertyElement.getAttribute("name"); 69 | String value = propertyElement.getAttribute("value"); 70 | 71 | Field declaredField = bean.getClass().getDeclaredField(name); 72 | declaredField.setAccessible(true); 73 | 74 | if (value != null && value.length() > 0) { 75 | declaredField.set(bean, value); 76 | } else { 77 | String ref = propertyElement.getAttribute("ref"); 78 | if (ref == null || ref.length() == 0) { 79 | throw new IllegalArgumentException("ref config error"); 80 | } 81 | 82 | declaredField.set(bean, getBean(ref)); 83 | } 84 | 85 | // 将 bean 注册到 bean 容器中 86 | registerBean(id, bean); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | private void registerBean(String id, Object bean) { 94 | beanMap.put(id, bean); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/Car.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring; 2 | 3 | /** 4 | * Created by code4wt on 17/8/2. 5 | */ 6 | public class Car { 7 | 8 | private String name; 9 | 10 | private String length; 11 | 12 | private String width; 13 | 14 | private String height; 15 | 16 | private Wheel wheel; 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public void setName(String name) { 23 | this.name = name; 24 | } 25 | 26 | public String getLength() { 27 | return length; 28 | } 29 | 30 | public void setLength(String length) { 31 | this.length = length; 32 | } 33 | 34 | public String getWidth() { 35 | return width; 36 | } 37 | 38 | public void setWidth(String width) { 39 | this.width = width; 40 | } 41 | 42 | public String getHeight() { 43 | return height; 44 | } 45 | 46 | public void setHeight(String height) { 47 | this.height = height; 48 | } 49 | 50 | public Wheel getWheel() { 51 | return wheel; 52 | } 53 | 54 | public void setWheel(Wheel wheel) { 55 | this.wheel = wheel; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return "Car{" + 61 | "name='" + name + '\'' + 62 | ", length='" + length + '\'' + 63 | ", width='" + width + '\'' + 64 | ", height='" + height + '\'' + 65 | ", \nwheel=" + wheel + 66 | '}'; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring; 2 | 3 | /** 4 | * Created by code4wt on 17/8/17. 5 | */ 6 | public interface HelloService { 7 | 8 | void sayHelloWorld(); 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring; 2 | 3 | /** 4 | * Created by code4wt on 17/8/17. 5 | */ 6 | public class HelloServiceImpl implements HelloService { 7 | 8 | @Override 9 | public void sayHelloWorld() { 10 | System.out.println("hello world!"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/Wheel.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring; 2 | 3 | /** 4 | * Created by code4wt on 17/8/2. 5 | */ 6 | public class Wheel { 7 | 8 | private String brand; 9 | 10 | private String specification ; 11 | 12 | public String getBrand() { 13 | return brand; 14 | } 15 | 16 | public void setBrand(String brand) { 17 | this.brand = brand; 18 | } 19 | 20 | public String getSpecification() { 21 | return specification; 22 | } 23 | 24 | public void setSpecification(String specification) { 25 | this.specification = specification; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "Wheel{" + 31 | "brand='" + brand + '\'' + 32 | ", specification='" + specification + '\'' + 33 | '}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/aop/AspectJExpressionPointcutTest.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import com.titizz.simulation.toyspring.HelloService; 4 | import com.titizz.simulation.toyspring.HelloServiceImpl; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertTrue; 8 | 9 | /** 10 | * Created by code4wt on 17/8/17. 11 | */ 12 | public class AspectJExpressionPointcutTest { 13 | 14 | @Test 15 | public void testClassFilter() throws Exception { 16 | String expression = "execution(* com.titizz.simulation.toyspring.*.*(..))"; 17 | AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); 18 | aspectJExpressionPointcut.setExpression(expression); 19 | boolean matches = aspectJExpressionPointcut.matchers(HelloService.class); 20 | assertTrue(matches); 21 | } 22 | 23 | @Test 24 | public void testMethodMatcher() throws Exception { 25 | String expression = "execution(* com.titizz.simulation.toyspring.*.sayHelloWorld(..))"; 26 | AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); 27 | aspectJExpressionPointcut.setExpression(expression); 28 | boolean matches = aspectJExpressionPointcut.matchers( 29 | HelloServiceImpl.class.getDeclaredMethod("sayHelloWorld"), HelloServiceImpl.class); 30 | assertTrue(matches); 31 | } 32 | } -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/aop/JdkDynamicAopProxyTest.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import com.titizz.simulation.toyspring.HelloService; 4 | import com.titizz.simulation.toyspring.HelloServiceImpl; 5 | import org.junit.Test; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * Created by code4wt on 17/8/17. 11 | */ 12 | public class JdkDynamicAopProxyTest { 13 | 14 | @Test 15 | public void getProxy() throws Exception { 16 | System.out.println("---------- no proxy ----------"); 17 | HelloService helloService = new HelloServiceImpl(); 18 | helloService.sayHelloWorld(); 19 | 20 | System.out.println("\n----------- proxy -----------"); 21 | AdvisedSupport advisedSupport = new AdvisedSupport(); 22 | advisedSupport.setMethodInterceptor(new LogInterceptor()); 23 | 24 | TargetSource targetSource = new TargetSource( 25 | helloService, HelloServiceImpl.class, HelloServiceImpl.class.getInterfaces()); 26 | advisedSupport.setTargetSource(targetSource); 27 | advisedSupport.setMethodMatcher((Method method, Class beanClass) -> true); 28 | 29 | helloService = (HelloService) new JdkDynamicAopProxy(advisedSupport).getProxy(); 30 | helloService.sayHelloWorld(); 31 | } 32 | } -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/aop/LogInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.aop; 2 | 3 | import org.aopalliance.intercept.MethodInterceptor; 4 | import org.aopalliance.intercept.MethodInvocation; 5 | 6 | /** 7 | * Created by code4wt on 17/8/17. 8 | */ 9 | public class LogInterceptor implements MethodInterceptor { 10 | 11 | @Override 12 | public Object invoke(MethodInvocation invocation) throws Throwable { 13 | System.out.println(invocation.getMethod().getName() + " method start"); 14 | Object obj= invocation.proceed(); 15 | System.out.println(invocation.getMethod().getName() + " method end"); 16 | return obj; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/ioc/XmlBeanFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.ioc; 2 | 3 | import com.titizz.simulation.toyspring.Car; 4 | import com.titizz.simulation.toyspring.HelloService; 5 | import com.titizz.simulation.toyspring.Wheel; 6 | import com.titizz.simulation.toyspring.ioc.xml.XmlBeanFactory; 7 | import org.junit.Test; 8 | 9 | /** 10 | * Created by code4wt on 17/8/2. 11 | */ 12 | public class XmlBeanFactoryTest { 13 | 14 | @Test 15 | public void getBean() throws Exception { 16 | System.out.println("--------- IOC test ----------"); 17 | String location = getClass().getClassLoader().getResource("toy-spring.xml").getFile(); 18 | XmlBeanFactory bf = new XmlBeanFactory(location); 19 | Wheel wheel = (Wheel) bf.getBean("wheel"); 20 | System.out.println(wheel); 21 | Car car = (Car) bf.getBean("car"); 22 | System.out.println(car); 23 | 24 | System.out.println("\n--------- AOP test ----------"); 25 | HelloService helloService = (HelloService) bf.getBean("helloService"); 26 | helloService.sayHelloWorld(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/simple/SimpleAOPTest.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.simple; 2 | 3 | import com.titizz.simulation.toyspring.HelloService; 4 | import com.titizz.simulation.toyspring.HelloServiceImpl; 5 | import org.junit.Test; 6 | 7 | /** 8 | * Created by code4wt on 17/8/19. 9 | */ 10 | public class SimpleAOPTest { 11 | 12 | @Test 13 | public void getProxy() throws Exception { 14 | // 1. 创建一个 MethodInvocation 实现类 15 | MethodInvocation logTask = () -> System.out.println("log task start"); 16 | HelloServiceImpl helloServiceImpl = new HelloServiceImpl(); 17 | 18 | // 2. 创建一个 Advice 19 | Advice beforeAdvice = new BeforeAdvice(helloServiceImpl, logTask); 20 | 21 | // 3. 为目标对象生成代理 22 | HelloService helloServiceImplProxy = (HelloService) SimpleAOP.getProxy(helloServiceImpl,beforeAdvice); 23 | 24 | helloServiceImplProxy.sayHelloWorld(); 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/java/com/titizz/simulation/toyspring/simple/SimpleIOCTest.java: -------------------------------------------------------------------------------- 1 | package com.titizz.simulation.toyspring.simple; 2 | 3 | import com.titizz.simulation.toyspring.Car; 4 | import com.titizz.simulation.toyspring.Wheel; 5 | import org.junit.Test; 6 | 7 | /** 8 | * Created by code4wt on 17/8/19. 9 | */ 10 | public class SimpleIOCTest { 11 | 12 | @Test 13 | public void getBean() throws Exception { 14 | String location = SimpleIOC.class.getClassLoader().getResource("toy-spring-ioc.xml").getFile(); 15 | SimpleIOC bf = new SimpleIOC(location); 16 | Wheel wheel = (Wheel) bf.getBean("wheel"); 17 | System.out.println(wheel); 18 | Car car = (Car) bf.getBean("car"); 19 | System.out.println(car); 20 | } 21 | } -------------------------------------------------------------------------------- /src/test/resources/toy-spring-ioc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/test/resources/toy-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | --------------------------------------------------------------------------------