tiny spring ioc 看到这个项目的第一反应仅仅是好玩,所以看看它到底能不能让我搞懂 spring …
该项目中共包含以下 10 个标签。
1 2 3 4 5 6 7 8 9 10 step-1-container-register-and-get step-2-abstract-beanfactory-and-do-bean-initilizing-in-it step-3-inject-bean-with-property step-4-config-beanfactory-with-xml step-5-inject-bean-to-bean step-6-invite-application-context step-7-method-interceptor-by-jdk-dynamic-proxy step-8-invite-pointcut-and-aspectj step-9-auto-create-aop-proxy step-10-invite-cglib-and-aopproxy-factory
step-1-container-register-and-get 从名字知道大概是说容器、注册机,从 Bean
开始,我们创建一个初始的 Bean
对象 ( BeanDefinition
):
1 2 3 4 5 6 7 8 9 10 11 public class BeanDefinition { private Object bean; public BeanDefinition (Object bean) { this .bean = bean; } public Object getBean () { return bean; } }
在 spring 中,我们需要一个 IoC 容器,我们创建一个工厂来保存 Bean ,这里命名 BeanFactory
:
1 2 3 4 5 6 7 8 9 10 11 public class BeanFactory { private 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); } }
这是一个比较普通的工厂方法模式,我比较关注的反而是 ConcurrentHashMap
,这个对象在原子性上是线程安全的,但是如果是复合操作的话,可能导致线程不安全,当我们简单对方法加上 synchronized
关键字,这也会出现问题。
因为 synchronized
关键字其本质都是锁定某一个对象,修饰方法的时候,锁上的是调用这个方法的对象,即 this ;修饰代码块的时候,锁上的是代码块里的对象。
但是如果我们对 Map
对象加上锁的话, ConcurrentHashMap
对象的作用就大了。
PS: 最后特别补充的是, synchronized
关键字判断对象是否是它属于锁定的对象,本质上是通过 == 运算符来判断的。换句话说,上面的代码中,可以采用任何一个常量,或者每个线程都共享的变量,或者类的静态变量,来代替 Map
。只要该变量与 synchronized
锁定的目标变量相同(==),就可以使 synchronized
生效。
值得注意的是,这里的 BeanDefinition
的构造器中使用的是 Object
对象,这方便我们创建真正的 Bean
对象的时候不用在意它的类型,这里我们创建一个需要使用的 Service
对象:
1 2 3 4 5 public class HelloWorldService { public void helloWorld () { System.out.println("Hello World!" ); } }
在具体测试这个 Service
的时候我们创建一个响应的 Test
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class BeanFactoryTest { @Test public void test () { BeanFactory beanFactory = new BeanFactory(); BeanDefinition beanDefinition = new BeanDefinition(new HelloWorldService()); beanFactory.registerBeanDefinition("helloWorldService" , beanDefinition); HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService" ); helloWorldService.helloWorld(); } }
运行这个测试程序发生了什么呢?
首先初始化一个 Bean
工厂;初始化一个具体的 Bean
,这里面包装一个需要工作的具体 Service
;把这个 Service
放到工厂里,比如用一个 Map
来存放,使用的使用,可以直接通过 key
取出这个具体的 Bean
,取出具体的 Service
,然后执行具体的 Service
方法。
step-2-abstract-beanfactory-and-do-bean-initilizing-in-it 题目取名叫做抽象工厂和 Bean
的初始化,回忆一下,工厂方法模式是为了创造一个系列,而抽象工厂模式是为了创造多个系列,这也是这里分层出一个具体 Factory
原因。
首先我们还是先创造一个 Bean
的外壳:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class BeanDefinition { private Object bean; private Class beanClass; private String beanClassName; public BeanDefinition () { } 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(); } } public Object getBean () { return bean; } }
和之前的区别在于,这里增加了对内部 Bean
的实例化。
最外层是一个工厂接口 BeanFactory
:
1 2 3 4 5 public interface BeanFactory { Object getBean (String name) ; void registerBeanDefinition (String name, BeanDefinition beanDefinition) ; }
然后是一个基础的实现 AbstractBeanFactory
,这里是基本方法的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public abstract class AbstractBeanFactory implements BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(); @Override public Object getBean (String name) { return beanDefinitionMap.get(name).getBean(); } @Override public void registerBeanDefinition (String name, BeanDefinition beanDefinition) { Object bean = doCreateBean(beanDefinition); beanDefinition.setBean(bean); beanDefinitionMap.put(name, beanDefinition); } protected abstract Object doCreateBean (BeanDefinition beanDefinition) ; }
这就是之前的工厂,它增加一个未实行的方法,用来具体产生 Bean
,最外层我们再包装一层:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 ; } }
测试的时候,创建一个具体的 Service
:
1 2 3 4 5 public class HelloWorldService { public void helloWorld () { System.out.println("Hello World!" ); } }
在具体测试的时候:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class BeanFactoryTest { @Test public void test () { BeanFactory beanFactory = new AutowireCapableBeanFactory(); BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanClassName("cool.koon.step2.HelloWorldService" ); beanFactory.registerBeanDefinition("helloWorldService" , beanDefinition); HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService" ); helloWorldService.helloWorld(); } }
和之前的差别在于,不再是我们手动创建具体的 Bean
对象,而是在外层对象中根据反射实例化对象。
step-3-inject-bean-with-property 这一章中是将属性注入到 Bean
中,此前我们仅仅是创建一个 Bean
,现在我们可以将具体的属性也实例化。
从属性对象开始创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class PropertyValue { private final String name; private final Object value; public PropertyValue (String name, Object value) { this .name = name; this .value = value; } public String getName () { return name; } public Object getValue () { return value; } }
以及属性对象的集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class PropertyValues { private final List<PropertyValue> propertyValueList = new ArrayList(); public PropertyValues () {} public void addPropertyValue (PropertyValue pv) { this .propertyValueList.add(pv); } public List<PropertyValue> getPropertyValues () { return this .propertyValueList; } }
现在我们的 Bean
需要包含属性对象的集合:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class BeanDefinition { private Object bean; private Class beanClass; private String beanClassName; private PropertyValues propertyValues; public BeanDefinition () { } 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(); } } public Object getBean () { return bean; } public PropertyValues getPropertyValues () { return propertyValues; } public void setPropertyValues (PropertyValues propertyValues) { this .propertyValues = propertyValues; } }
Bean
工厂还是使用抽象工厂模式创建,首先是最外层的工厂接口:
1 2 3 4 5 public interface BeanFactory { Object getBean (String name) ; void registerBeanDefinition (String name, BeanDefinition beanDefinition) throws Exception ; }
然后是创建抽象类,完成一部分的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public abstract class AbstractBeanFactory implements BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(); @Override public Object getBean (String name) { return beanDefinitionMap.get(name).getBean(); } @Override public void registerBeanDefinition (String name, BeanDefinition beanDefinition) throws Exception { Object bean = doCreateBean(beanDefinition); beanDefinition.setBean(bean); beanDefinitionMap.put(name, beanDefinition); } protected abstract Object doCreateBean (BeanDefinition beanDefinition) throws Exception ; }
最后是具体的工厂类,除了实现上面我们定义的 doCreateBean
方法,我们还需要指定属性对象的创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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 mbd) throws Exception { for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) { Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName()); declaredField.setAccessible(true ); declaredField.set(bean, propertyValue.getValue()); } } }
测试的时候先指定确定的 Service
对象:
1 2 3 4 5 6 7 8 9 10 11 public class HelloWorldService { private String text; public void helloWorld () { System.out.println(text); } public void setText (String text) { this .text = text; } }
然后我们开始测试我们现在的抽象工厂,这里我们还需要创建属性的集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class BeanFactoryTest { @Test public void test () throws Exception { BeanFactory beanFactory = new AutowireCapableBeanFactory(); BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanClassName("cool.koon.step3.HelloWorldService" ); PropertyValues propertyValues = new PropertyValues(); propertyValues.addPropertyValue(new PropertyValue("text" , "Hello World!" )); beanDefinition.setPropertyValues(propertyValues); beanFactory.registerBeanDefinition("helloWorldService" , beanDefinition); HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService" ); helloWorldService.helloWorld(); } }
总体基调还是一个抽象工厂。
这里使用 Field
来设置属性,实际中我们都会使用 setter 等方法。
Field
对象就代替了属性的地位,直接对它设置值就可以进行属性赋值。
step-4-config-beanfactory-with-xml 根据题目的意思我们开始使用 xml
来配置工厂,来看一看吧。
首先老样子,我们创建一个 Bean
的包装:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class BeanDefinition { private Object bean; private Class beanClass; private String beanClassName; private PropertyValues propertyValues = new PropertyValues(); public BeanDefinition () { } 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(); } } public Object getBean () { return bean; } public PropertyValues getPropertyValues () { return propertyValues; } public void setPropertyValues (PropertyValues propertyValues) { this .propertyValues = propertyValues; } }
同时还需要创建属性类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class PropertyValue { private final String name; private final Object value; public PropertyValue (String name, Object value) { this .name = name; this .value = value; } public String getName () { return name; } public Object getValue () { return value; } }
还有属性列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class PropertyValues { private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>(); public PropertyValues () { } public void addPropertyValue (PropertyValue pv) { this .propertyValueList.add(pv); } public List<PropertyValue> getPropertyValues () { return this .propertyValueList; } }
现在我们来到 io
包,首先创建一个 Resource
接口:
1 2 3 public interface Resource { InputStream getInputStream () throws IOException ; }
对它继承:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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(); } }
比较直接,开启一个 url
,连接后获得一个字节流。
再来一个类来获得这个 UrlResource
:
1 2 3 4 5 6 public class ResourceLoader { public Resource getResource (String location) { URL resource = this .getClass().getClassLoader().getResource(location); return new UrlResource(resource); } }
现在使用抽象工厂的形式,我们创建一个接口,以及一个部分实现的阅读器,最后是一个 xml
的读取器。首先是一个 Bean
接口:
1 2 3 public interface BeanDefinitionReader { void loadBeanDefinitions (String location) throws Exception ; }
然后是一个抽象类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader { private Map<String,BeanDefinition> registry; private ResourceLoader resourceLoader; protected AbstractBeanDefinitionReader (ResourceLoader resourceLoader) { this .registry = new HashMap<String, BeanDefinition>(); this .resourceLoader = resourceLoader; } public Map<String, BeanDefinition> getRegistry () { return registry; } public ResourceLoader getResourceLoader () { return resourceLoader; } }
最后 xml
包里实现一个 XmlBeanDefinitionReader
:
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 26 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 { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = factory.newDocumentBuilder(); Document doc = docBuilder.parse(inputStream); registerBeanDefinitions(doc); inputStream.close(); } public void registerBeanDefinitions (Document doc) { Element root = doc.getDocumentElement(); parseBeanDefinitions(root); } }
我们不需要太了解它是怎么解析这个 xml
的,只要知道它达到的效果是从中取出属性并赋值。
下面是工厂的搭建,从工厂的接口开始:
1 2 3 4 5 public interface BeanFactory { Object getBean (String name) ; void registerBeanDefinition (String name, BeanDefinition beanDefinition) throws Exception ; }
我们创建一个抽象类来部分实现这个工厂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public abstract class AbstractBeanFactory implements BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(); @Override public Object getBean (String name) { return beanDefinitionMap.get(name).getBean(); } @Override public void registerBeanDefinition (String name, BeanDefinition beanDefinition) throws Exception { Object bean = doCreateBean(beanDefinition); beanDefinition.setBean(bean); beanDefinitionMap.put(name, beanDefinition); } protected abstract Object doCreateBean (BeanDefinition beanDefinition) throws Exception ; }
老样子,最后创建一个具体的工厂类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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 mbd) throws Exception { for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) { Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName()); declaredField.setAccessible(true ); declaredField.set(bean, propertyValue.getValue()); } } }
下面开始实现测试类。
老样子创建一个 Service
:
1 2 3 4 5 6 7 8 9 10 11 public class HelloWorldService { private String text; public void helloWorld () { System.out.println(text); } public void setText (String text) { this .text = text; } }
现在我们创建一个测试方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class BeanFactoryTest { @Test public void test () throws Exception { XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml" ); BeanFactory beanFactory = new AutowireCapableBeanFactory(); for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) { beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue()); } HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService" ); helloWorldService.helloWorld(); } }
不要以为这里用了两个抽象工厂,这个方式就变复杂了,仅仅看似复杂,实际上非常普通,仅仅是从手动输入各个属性到现在从 xml
中读取属性。
step-5-inject-bean-to-bean 这一章节使用的是指在 Bean
中注入 Bean
,我们来看看它的实现。
这里,我们连接上一个项目,在其上直接进行修改。
首先,我们需要定义一个类作为 Bean
的注入:
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 public class BeanReference { private String name; private Object bean; public BeanReference (String name) { this .name = name; } public String getName () { return name; } public void setName (String name) { this .name = name; } public Object getBean () { return bean; } public void setBean (Object bean) { this .bean = bean; } }
它作为另外一个 Bean
被注入到一个 Bean
中,具体操作在 XmlBeanDefinitionReader
中:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 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 { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = factory.newDocumentBuilder(); Document doc = docBuilder.parse(inputStream); registerBeanDefinitions(doc); inputStream.close(); } public void registerBeanDefinitions (Document doc) { Element root = doc.getDocumentElement(); parseBeanDefinitions(root); } protected void parseBeanDefinitions (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 = new BeanDefinition(); processProperty(ele,beanDefinition); beanDefinition.setBeanClassName(className); getRegistry().put(name, beanDefinition); } private 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" ); if (value != null && value.length() > 0 ) { beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value)); } else { String ref = propertyEle.getAttribute("ref" ); if (ref == null || ref.length() == 0 ) { throw new IllegalArgumentException("Configuration problem: <property> element for property '" + name + "' must specify a ref or value" ); } BeanReference beanReference = new BeanReference(ref); beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference)); } } } } }
这里是将 xml
的内容读取,在 Bean
工厂中,我们具体使用:
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 26 27 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 mbd) throws Exception { for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) { Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName()); declaredField.setAccessible(true ); Object value = propertyValue.getValue(); if (value instanceof BeanReference) { BeanReference beanReference = (BeanReference) value; value = getBean(beanReference.getName()); } declaredField.set(bean, value); } } }
这是主要修改的地方,另外因为现在我们的 Bean
包装中不止一种类了,所以还有一些小细节需要修改,比如每次手动确认 Bean
里的内容,如果 Bean
没有创建,我们需要再创建。
我们现在在 AbstractBeanFactory
中创建一个方法 getBean
用来实例化 Bean
:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public abstract class AbstractBeanFactory implements BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(); private final List<String> beanDefinitionNames = new ArrayList<String>(); @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); } return bean; } @Override 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 abstract Object doCreateBean (BeanDefinition beanDefinition) throws Exception ; }
最后我们进入测试:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class BeanFactoryTest { @Test public void testLazy () throws Exception { XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml" ); AbstractBeanFactory beanFactory = new AutowireCapableBeanFactory(); for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) { beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue()); } HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService" ); helloWorldService.helloWorld(); } @Test public void testPreInstantiate () throws Exception { XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); xmlBeanDefinitionReader.loadBeanDefinitions("tinyioc.xml" ); AbstractBeanFactory beanFactory = new AutowireCapableBeanFactory(); for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) { beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue()); } beanFactory.preInstantiateSingletons(); HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService" ); helloWorldService.helloWorld(); } }
这里的 OutputService
是另外一个 Bean
也是被注入的 Bean
,实现的时候需要注意哪个 Bean
属于哪个即可。
step-6-invite-application-context 终于来到了 IoC
实现的最后一章,这里 ApplicationContext
终于登场了。
我们把上面这些 xml
读取到属性插入的代码进行封装,这些组成代码现在是 Application
的部分,它也采用一个抽象工厂模式,分别是一个接口:
1 public interface ApplicationContext extends BeanFactory {}
这个接口继承自抽象工厂的接口,它这样写也是为了更好地传入参数,然后我们对它进行部分实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public abstract class AbstractApplicationContext implements ApplicationContext { protected AbstractBeanFactory beanFactory; public AbstractApplicationContext (AbstractBeanFactory beanFactory) { this .beanFactory = beanFactory; } @Override public Object getBean (String name) throws Exception { return beanFactory.getBean(name); } public void refresh () throws Exception { } }
然后是一个具体的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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 public void refresh () throws Exception { XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader()); xmlBeanDefinitionReader.loadBeanDefinitions(configLocation); for (Map.Entry<String, BeanDefinition> beanDefinitionEntry: xmlBeanDefinitionReader.getRegistry().entrySet()) { beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue()); } } }
我们在 refresh
方法中进行具体的实现,这里我们进行配置的读取,属性的注册等操作,等于在复现之前的测试方法。
现在测试方法就极端简单了:
1 2 3 4 5 6 7 8 public class ApplicationContextTest { @Test public void test () throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml" ); HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService" ); helloWorldService.helloWorld(); } }
一个简单的 IoC
通过几个简单的抽象工厂就完成了。
tiny spring aop step-7-method-interceptor-by-jdk-dynamic-proxy 这么快我们 IoC
就看完了,非常有意思,下面开始了 AOP
的学习,我们知道在 AOP
中分为配置和织入两部分,当然还有一部分是将 AOP
整合到整个容器的生命周期中。
三个点,一个被代理对象,一个拦截器,一个代理者,被代理对象被包装成一个 AdvisedSupport
其中包含我们具体的拦截器:
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 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; } }
然后我们实现一个具体拦截器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class TimerInterceptor implements MethodInterceptor { @Override public Object invoke (MethodInvocation methodInvocation) throws Throwable { long time = System.nanoTime(); System.out.println("Invocation of Method " + methodInvocation.getMethod().getName() + " start!" ); Object proceed = methodInvocation.proceed(); System.out.println("Invocation of Method " + methodInvocation.getMethod().getName() + " end! takes " + (System.nanoTime() - time) + " nanoseconds" ); return proceed; } }
紧接着,是一个代理者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class JdkDynamicAopProxy implements AopProxy , InvocationHandler { private AdvisedSupport advised; public JdkDynamicAopProxy (AdvisedSupport advised) { this .advised = advised; } @Override public Object getProxy () { return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { advised.getTargetSource().getTargetClass() }, this ); } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { MethodInterceptor methodInterceptor = advised.getMethodInterceptor(); return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args)); } }
还是比较好理解的一个 AOP
小例子。
step-8-invite-pointcut-and-aspectj 来到第 8 章,我们开始考虑一个问题,那就是什么时候进行 AOP
?对于这个问题,我们叫做 Pointcut
,在 Spring
的 Pointcut
中包含两个角色: ClassFilter
和 MethodMatcher
,分别是对类和方法做匹配,比较通用的方式是使用 AspectJ
表达式,但是为此我们需要学习一门语言又得不偿失,我们怎么做呢?
首先从两个接口开始,分别用来匹配类和方法,多实现在一个类中:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public class AspectJExpressionPointcut implements Pointcut , ClassFilter , MethodMatcher { private PointcutParser pointcutParser; private String expression; private PointcutExpression pointcutExpression; private static final Set<PointcutPrimitive> DEFAULT_SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>(); static { DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS); DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET); } public AspectJExpressionPointcut () { this (DEFAULT_SUPPORTED_PRIMITIVES); } public AspectJExpressionPointcut (Set<PointcutPrimitive> supportedPrimitives) { pointcutParser = PointcutParser .getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives); } protected void checkReadyToMatch () { if (pointcutExpression == null ) { pointcutExpression = buildPointcutExpression(); } } private PointcutExpression buildPointcutExpression () { return pointcutParser.parsePointcutExpression(expression); } public void setExpression (String expression) { this .expression = expression; } @Override public ClassFilter getClassFilter () { return this ; } @Override public MethodMatcher getMethodMatcher () { return this ; } @Override public boolean matches (Class targetClass) { checkReadyToMatch(); return pointcutExpression.couldMatchJoinPointsInType(targetClass); } @Override public boolean matches (Method method, Class targetClass) { checkReadyToMatch(); ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method); if (shadowMatch.alwaysMatches()) { return true ; } else if (shadowMatch.neverMatches()) { return false ; } return false ; } }
在测试类中用匹配的方式来切:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class AspectJExpressPointcutTest { @Test public void testClassFilter () throws Exception { String expression = "execution(* cool.koon.step4to6.*.*(..))" ; AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(expression); boolean matches = aspectJExpressionPointcut.getClassFilter().matches(HelloWorldService.class); Assert.assertTrue(matches); } @Test public void testMethodInterceptor () throws Exception { String expression = "execution(* cool.koon.step4to6.*.*(..))" ; AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut(); aspectJExpressionPointcut.setExpression(expression); boolean matches = aspectJExpressionPointcut.getMethodMatcher().matches(HelloWorldServiceImpl.class.getDeclaredMethod("helloWorld" ),HelloWorldServiceImpl.class); Assert.assertTrue(matches); } }
简单讲,这一章给我们一个便捷切面的方式,使用正则,指定类或者方法来进行 AOP
。
step-9-auto-create-aop-proxy 这里,我们已经拥有了 Pointcut
一个 AOP
已经完成,但是我们还没有结合到 Spring
中,现在我们给出一个答案 BeanPostProcessor
,它是 BeanFactory
提供的,在 Bean
继续初始化的过程中进行扩展。
核心点在于 AspectJAwareAdvisorAutoProxyCreator
这个类的 Spring
初始化的时候,会优先找到它们,并且在 Bean
初始化的过程中,调用这个接口,从而实现对 Spring
工厂的无侵入的扩展。
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor , BeanFactoryAware { private AbstractBeanFactory beanFactory; @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws Exception { return bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws Exception { if (bean instanceof AspectJExpressionPointcutAdvisor) { return bean; } if (bean instanceof MethodInterceptor) { return bean; } List<AspectJExpressionPointcutAdvisor> advisors = beanFactory .getBeansForType(AspectJExpressionPointcutAdvisor.class); for (AspectJExpressionPointcutAdvisor advisor : advisors) { if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) { AdvisedSupport advisedSupport = new AdvisedSupport(); advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher()); TargetSource targetSource = new TargetSource(bean, bean.getClass().getInterfaces()); advisedSupport.setTargetSource(targetSource); return new JdkDynamicAopProxy(advisedSupport).getProxy(); } } return bean; } @Override public void setBeanFactory (BeanFactory beanFactory) throws Exception { this .beanFactory = (AbstractBeanFactory) beanFactory; } }
有一种说法是 —— BeanPostProcessor
:在 postProcessorAfterInitialization
方法中,使用动态代理的方式,返回一个对象的代理对象。解决了在 IoC
容器的何处植入 AOP
的问题。
BeanFactoryAware
:这个接口提供了对 BeanFactory
的感知,这样,尽管它是容器中的一个 Bean
,却可以获取容器的引用,进而获取容器中所有的切点对象,决定对哪些对象的哪些方法进行代理。解决了为哪些对象提供 AOP
的植入的问题。
但是只能说有一定的道理。
step-10-invite-cglib-and-aopproxy-factory 最后了,我们现在只能对接口进行代理,对于类却无能为力,这里我们需要一些字节码的操作,使用 CGLib
,或者应该说是 jvm
动态擦除的历史遗留问题。
这个项目像是介绍性质地给我们看了看 IoC
和 AOP
的部分妙用,果然受益良多,最后实在不想重复劳作了,把 step4 到 step10 写到了一起。