1. IoC and AOP
IoC: Inversion of Control, or Dependency Injection(DI). In my understanding, it is we put business class and configuration file into Spring container, and then it can produce a system that all dependencies of class already done, which already can use.
The dependency information can be done by XML file, by Spring Annotations like @Autowired, or some Java Annotations like @Configuration.
AOP(Aspect Oriented Programming): Also comes from reality problems. Such as we have some functional modules, like User Management Module and Order Management Module, they not only have relationships with each other, also have relationships with some non-functional modules, such as log system and security system.
If we only in functional systems call non-functional systems, even only very small change of non-functional modules we need to change methods in functional modules. This can not be endured.
So we can isolate the functional codes and non-functional codes like this way.
2. Steps for unit test
One unit test has 4 steps:
- Think and write test cases: which always included corner cases and normal cases.
- Run the test case and find error.
- Write just enough code to make test cases.
- Refactor code to make it clean.
Then loop until all functions are developed.
3. Step1: How to build a class from XML file?
This is a class I call it DefaultBeanFactory
, which I used to generate bean from XML file.
First step, I used a package called dom4j
which maven format is this:
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
This package produce abilities for reading XML files. Use this, I can change XML file into inputStream and then read XML elements.
The XML file I want to analysis is this one:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="petStore"
class="org.litespring.service.v1.PetStoreService" >
</bean>
</beans>
So we can see the bean has elements id
and class
in pair. After analysis, I will put them into a map, so that we don;’t need to analysis it once and once again.
I use another class GenericBeanDefination
which implements the interface BeanDefination
, produces constructor like this:
package org.litespring.beans.factory.support;
import org.litespring.beans.BeanDefinition;
public class GenericBeanDefinition implements BeanDefinition {
private String id;
private String beanClassName;
public GenericBeanDefinition(String id, String beanClassName) {
this.id = id;
this.beanClassName = beanClassName;
}
public String getBeanClassName() {
return this.beanClassName;
}
}
Then I need one thing that can convert BeanDefination
into Class, which is a classloader
. Here I use ClassUtil which jdk provided.
Simply saying, ClassUtil
has 3 steps to get a classLoader, the first step is to use Thread.currentThread().getContextClassLoader()
to get the currentThread’s context classloader. After that, it uses ClassUtils.class.getClassLoader()
to get itself’s classLoader
, then if still cannot get, it will use getSystemClassLoader()
, which is also the AppClassLoader
ClassLoader.getSystemClassLoader
will often returnApplicationClassLoader
, it only load class file underclasspath
,which is often the ` bin/in Java SE. And in Java EE,
Thread.currentThread().getContextClassLoader()also returns
ApplicationClassLoader`But in Java EE. class of our project is from
WebAppClassLoader
, which can be get from ` Thread.currentThread().getContextClassLoader()`.
Code is just from JDK, so I paste it here:
package org.litespring.util;
public abstract class ClassUtils {
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
}
After I get the classLoader, I can pass the name of class to create the class use reflection, then return an instance of the class, here in the first edition I just use the default constructor, which has no parameters.
try {
Class<?> clz = cl.loadClass(beanClassName);
return clz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Refactor code:
Here the way that try catch is not very easy to read, so I get some Exceptions to make the code cleaner. The relationship is like this:
BeanDefinationStoreException
is the Exception when I read XML file wrongly, and BeanCreationException
is the Exception when create the Bean wrongly.