Tiny-Spring項目學習總結

人生不相見,動如參與商.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();
}
}
相關文章
相關標籤/搜索