人生不相見,動如參與商.java
Spring基本是全部Java學習者繞不開的框架,其對於現代Java的開發具備里程碑式的做用,將java開發者從繁雜的框架和配置中解放出來(至少是部分解放出來)。在github上看到一個微型的spring框架實現項目,以爲頗有必要學習一下,誰知道斷斷續續用了三個月才徹底本身實現了一遍,本篇文章對於這個項目的學習作一個總結。node
談到Spring,咱們通常會想到它的IOC和AOP特性,也就是上圖的Core Containter和AOP以及Aspects部分。Tiny-Spring項目從最簡單的IOC容器類開始,實現了Spring的IOC和AOP的基本功能,git
先看下最基礎的對於bean的定義,如下是最簡單的bean定義,只包含了對於bean自己的設置和獲取方法:github
public class BeanDefinition { private Object bean; public BeanDefinition(Object bean){ this.bean = bean; } public Object getBean(){ return bean; } }
衆所周知,Spring使用工廠方法來管理bean,那麼咱們還須要一個最基礎的工廠類:spring
public class BeanFactory { Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(); public Object getBean(String name){ return beanDefinitionMap.get(name).getBean();} public void registerBeanDefinition(String name,BeanDefinition beanDefinition){ beanDefinitionMap.put(name,beanDefinition); } }
這樣的話咱們就實現了一個最簡單的bean管理功能,能夠測試一下。app
先定義一個pojo類:
public class HelloWorldService {框架
public void hello(){ System.out.println("Hello World"); } }
寫一個測試方法:ide
public class BeanFactoryTest { @Test public void init(){ //1.初始化BeanFactory BeanFactory beanFactory = new BeanFactory(); //2.注入Bean BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService()); beanFactory.registerBeanDefinition("helloWorldService",beanDefinition); //3.獲取Bean實例 HelloWorldService helloWorldService = (HelloWorldService)beanFactory.getBean("helloWorldService"); helloWorldService.hello(); } }
能夠看到,咱們沒有直接初始化pojo類的實例,而是將其註冊到bean工廠中,當須要調用的時候,再從工廠類中獲取並調用。性能
接下來,咱們須要將bean的初始化流程徹底放入bean工廠中,所以須要拓展咱們的BeanDefinition類:單元測試
public class BeanDefinition { private Object bean; private Class beanClass; private String beanClassName; public Object getBean() { return bean; } public void setBean(Object bean) { this.bean = bean; } public Class getBeanClass() { return beanClass; } public void setBeanClass(Class beanClass) { this.beanClass = beanClass; } public String getBeanClassName() { return beanClassName; } public void setBeanClassName(String beanClassName) { this.beanClassName = beanClassName; try{ this.beanClass = Class.forName(beanClassName); }catch (ClassNotFoundException e){ e.printStackTrace(); } } }
定義bean工廠接口,只須要獲取和設置bean的方法:
public interface BeanFactory { Object getBean(String beanName); void registerBeanDefinition(String beanName, BeanDefinition beanDefinition); }
定義抽象bean工廠類,實現獲取和設置bean的方法,抽象初始化bean的方法:
public abstract class AbstractBeanFactory implements BeanFactory{ private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>(); @Override public Object getBean(String beanName) { return beanDefinitionMap.get(beanName).getBean(); } @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) { Object bean = doCreateBean(beanDefinition); beanDefinition.setBean(bean); beanDefinitionMap.put(beanName,beanDefinition); } /** * 建立Bean實例 * @param beanDefinition * @return */ protected abstract Object doCreateBean(BeanDefinition beanDefinition); }
最後,具體的bean工廠類,實現初始化bean的方法(此處經過反射初始化bean實例):
public class AutowireCapableBeanFactory extends AbstractBeanFactory{ @Override protected Object doCreateBean(BeanDefinition beanDefinition) { try { Object bean = beanDefinition.getBeanClass().newInstance(); return bean; }catch (InstantiationException e){ e.printStackTrace(); }catch (IllegalAccessException e){ e.printStackTrace(); } return null; } }
編寫對應的單元測試類;
public class BeanFactoryTest { @Test public void init(){ BeanFactory beanFactory = new AutowireCapableBeanFactory(); BeanDefinition beanDefinition = new BeanDefinition(); // Spring使用反射來初始化bean實例,所以須要輸入全限定名(涉及到動態編譯的性能問題,lazy init)) beanDefinition.setBeanClassName("com.simon.HelloWorldService"); //將bean註冊到工廠 beanFactory.registerBeanDefinition("helloService",beanDefinition); HelloWorldService helloWorldService = (HelloWorldService)beanFactory.getBean("helloService"); helloWorldService.sayHello(); } }
下一步,若是pojo類具備屬性,咱們的bean工廠在初始化bean實例的時候須要能爲其設置對應的屬性值。
首先,拓展咱們的BeanDefinition類:
public class BeanDefinition { private Object bean; private String beanClassName; private Class beanClass; private PropertyValues propertyValues; public BeanDefinition() { } public Object getBean() { return bean; } public void setBean(Object bean) { this.bean = bean; } public String getBeanClassName() { return beanClassName; } public void setBeanClassName(String beanClassName) { this.beanClassName = beanClassName; try{ this.beanClass = Class.forName(beanClassName); }catch(ClassNotFoundException e){ e.printStackTrace(); } } public Class getBeanClass() { return beanClass; } public void setBeanClass(Class beanClass) { this.beanClass = beanClass; } public PropertyValues getPropertyValues() { return propertyValues; } public void setPropertyValues(PropertyValues propertyValues) { this.propertyValues = propertyValues; } @Override public String toString() { return "BeanDefinition{" + "bean=" + bean + ", beanClassName='" + beanClassName + '\'' + ", beanClass=" + beanClass + ", propertyValues=" + propertyValues + '}'; } }
這裏咱們的具體工廠實現類須要修改,在初始化bean的時候將屬性值設置進去:
public class AutowireCapableBeanFactory extends AbstractBeanFactory{ @Override protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception { Object bean = createBeanInstance(beanDefinition); applyPropertyValues(bean, beanDefinition); return bean; } protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception { return beanDefinition.getBeanClass().newInstance(); } protected void applyPropertyValues(Object bean,BeanDefinition beanDefinition) throws Exception{ for(PropertyValue pv:beanDefinition.getPropertyValues().getPropertyValueList()){ Field declaredField = bean.getClass().getDeclaredField(pv.getKey()); //使用反射繞過private限制爲字段直接賦值 declaredField.setAccessible(true); declaredField.set(bean,pv.getValue()); } } }
對應的單元測試方法:
public class BeanFactoryTest { @Test public void test() throws Exception { // 1.初始化beanfactory BeanFactory beanFactory = new AutowireCapableBeanFactory(); // 2.bean定義 BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanClassName("com.simon.HelloWorldService"); // 3.設置屬性 PropertyValues propertyValues = new PropertyValues(); propertyValues.addProperty(new PropertyValue("text", "Hello World!")); beanDefinition.setPropertyValues(propertyValues); // 4.生成bean beanFactory.registerBeanDefinition("helloWorldService", beanDefinition); // 5.獲取bean HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService"); helloWorldService.helloWorld(); } }
接下來,咱們要實現從配置文件讀取bean的定義。
首先,定義配置文件資源定義接口:
public interface Resource { /** * 經過輸入流獲取資源 * * @return * @throws IOException */ InputStream getInputStream() throws IOException; }
具體的資源類;
public class URLResource implements Resource{ private final URL url; public URLResource(URL url) { this.url = url; } @Override public InputStream getInputStream() throws IOException { URLConnection urlConnection = url.openConnection(); urlConnection.connect(); return urlConnection.getInputStream(); } }
實現資源讀取類:
public class ResourceLoader { public Resource getResource(String location){ URL resource = this.getClass().getClassLoader().getResource(location); return new URLResource(resource); } }
接下來咱們要實現從資源中讀取的BeanDefinition的功能。
首先定義讀取BeanDefinition的接口:
public interface BeanDefinitionReader { void loadBeanDefinitions(String location) throws Exception; }
抽象的BeanDefinition讀取類,含有一個資源讀取類和BeanDefinition集合:
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader{ private Map<String,BeanDefinition> registry; private ResourceLoader resourceLoader; public AbstractBeanDefinitionReader(ResourceLoader resourceLoader) { this.registry = new HashMap<String, BeanDefinition>(); this.resourceLoader = resourceLoader; } public Map<String, BeanDefinition> getRegistry() { return registry; } public ResourceLoader getResourceLoader() { return resourceLoader; } }
具體的BeanDefinition讀取類,從xml讀取bean定義並解析,經過name-bean映射到map存儲bean的信息;
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader{ public XmlBeanDefinitionReader(ResourceLoader resourceLoader) { super(resourceLoader); } @Override public void loadBeanDefinitions(String location) throws Exception { InputStream inputStream = getResourceLoader().getResource(location).getInputStream(); doLoadBeanDefinitions(inputStream); } protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception{ //建立xml解析器 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(inputStream); registerBeanDefinitions(doc); inputStream.close(); } public void registerBeanDefinitions(Document doc){ Element root = doc.getDocumentElement(); parseDeanDefinitions(root); } protected void parseDeanDefinitions(Element root){ NodeList nl = root.getChildNodes(); for(int i= 0;i<nl.getLength();i++){ Node node = nl.item(i); if(node instanceof Element){ Element ele = (Element)node; processBeanDefinition(ele); } } } protected void processBeanDefinition(Element ele){ String name = ele.getAttribute("name"); String className = ele.getAttribute("class"); //建立BeanDefinition對象 BeanDefinition beanDefinition = new BeanDefinition(); processProperty(ele,beanDefinition); beanDefinition.setBeanClassName(className); getRegistry().put(name,beanDefinition); } protected void processProperty(Element ele,BeanDefinition beanDefinition){ NodeList propertyNode = ele.getElementsByTagName("property"); for(int i=0;i<propertyNode.getLength();i++){ Node node = propertyNode.item(i); if(node instanceof Element){ Element propertyEle = (Element)node; String name = propertyEle.getAttribute("name"); String value = propertyEle.getAttribute("value"); beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name,value)); } } } }
接下來定義一個bean的配置文件studyTiny.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <bean name="helloWorldService" class="com.simon.HelloWorldService"> <property name="text" value="Hello World!"></property> </bean> </beans>
對應的單元測試類:
public class XmlBeanDefinitionReaderTest { @Test public void test() throws Exception { XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); xmlBeanDefinitionReader.loadBeanDefinitions("studyTiny.xml"); Map<String, BeanDefinition> registry = xmlBeanDefinitionReader.getRegistry(); Assert.assertTrue(registry.size() > 0); } }
接下來,引入咱們熟悉的ApplicationContext.
定義ApplicationContext接口,繼承BeanFactory,具有管理bean的能力:
public interface ApplicationContext extends BeanFactory { }
定義抽象類,注入工廠管理bean:
public abstract class AbstractApplicationContext implements ApplicationContext{ protected AbstractBeanFactory beanFactory; public AbstractApplicationContext(AbstractBeanFactory abstractBeanFactory) { this.beanFactory = abstractBeanFactory; } public abstract void refresh() throws Exception; @Override public Object getBean(String name) throws Exception { return beanFactory.getBean(name); } }
最後實現基於xml定義bean的容器類:
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{ private String configLocation; public ClassPathXmlApplicationContext(String configLocation) throws Exception{ this(configLocation,new AutowireCapableBeanFactory()); } public ClassPathXmlApplicationContext(String configLocation,AbstractBeanFactory abstractBeanFactory) throws Exception{ super(abstractBeanFactory); this.configLocation = configLocation; refresh(); } @Override public void refresh() throws Exception { //使用xml的bean讀取器獲取bean的定義 XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); xmlBeanDefinitionReader.loadBeanDefinitions(configLocation); for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) { beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue()); } } }
單元測試類;
public class ApplicationContextTest { @Test public void test() throws Exception{ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("studyTiny.xml"); HelloWorldService helloWorldService = (HelloWorldService)applicationContext.getBean("helloWorldService"); helloWorldService.helloWorld(); } }
接下來咱們來實現AOP功能,AOP有Pointcut(切入點), Advice(功能加強)以及織入weave,固然咱們還須要將AOP整合到Spring的生命週期中。
首先定義被代理對象:
public class TargetSource { private Class targetClass; private Object target; public TargetSource(Class<?> targetClass, Object target) { this.targetClass = targetClass; this.target = target; } public Class getTargetClass() { return targetClass; } public Object getTarget() { return target; } }
代理相關的元數據類:
public class AdvisedSupport { private TargetSource targetSource; private MethodInterceptor methodInterceptor; public TargetSource getTargetSource() { return targetSource; } public void setTargetSource(TargetSource targetSource) { this.targetSource = targetSource; } public MethodInterceptor getMethodInterceptor() { return methodInterceptor; } public void setMethodInterceptor(MethodInterceptor methodInterceptor) { this.methodInterceptor = methodInterceptor; } }
切入點對象;
public class ReflectiveMethodInvocation implements MethodInvocation { /** 被代理類 */ private Object target; /** 被代理的方法 */ private Method method; /** 方法入參 */ private Object[] args; public ReflectiveMethodInvocation(Object target, Method method, Object[] args) { this.target = target; this.method = method; this.args = args; } @Override public Method getMethod() { return method; } @Override public Object[] getArguments() { return args; } /** * 調用被代理方法 * @return * @throws Throwable */ @Override public Object proceed() throws Throwable { return method.invoke(target,args); } @Override public Object getThis() { return target; } /** * 獲取被調用方法 * @return */ @Override public AccessibleObject getStaticPart() { return method; } }
代理接口:
public interface AopProxy { Object getProxy(); }
JDK代理類:
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler { private AdvisedSupport advisedSupport; public JdkDynamicAopProxy(AdvisedSupport advisedSupport) { this.advisedSupport = advisedSupport; } /** * 使用jdk的動態代理獲取代理對象 * @return */ @Override public Object getProxy() { return Proxy.newProxyInstance(getClass().getClassLoader(),new Class[]{ advisedSupport.getTargetSource().getTargetClass() },this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInterceptor methodInterceptor = advisedSupport.getMethodInterceptor(); return methodInterceptor.invoke(new ReflectiveMethodInvocation(advisedSupport.getTargetSource().getTarget(),method,args)); } }
接下來能夠測試了,先定義一個攔截器類:
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!"); Object proceed = invocation.proceed(); System.out.println("Invocation of Method "+invocation.getMethod().getName()+" ends! takes "+(System.nanoTime() - time )); return proceed; } }
接下來寫單元測試類:
public class JdkDynamicAopProxyTest { @Test public void test() throws Exception{ //init context ApplicationContext applicationContext = new ClassPathXmlApplicationContext("studyTiny.xml"); //helloWorldService without aop HelloWorldService helloWorldService = (HelloWorldService)applicationContext.getBean("helloWorldService"); helloWorldService.helloWorld();; //helloWorldService with aop AdvisedSupport advisedSupport = new AdvisedSupport(); TargetSource targetSource = new TargetSource(HelloWorldService.class,helloWorldService); advisedSupport.setTargetSource(targetSource); //set interceptor TimerInterceptor timerInterceptor = new TimerInterceptor(); advisedSupport.setMethodInterceptor(timerInterceptor); //set proxy JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport); HelloWorldService helloWorldProxy = (HelloWorldService)jdkDynamicAopProxy.getProxy(); helloWorldProxy.helloWorld(); } }