Tiny-Spring项目学习总结
Posted ShoolyShooly
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tiny-Spring项目学习总结相关的知识,希望对你有一定的参考价值。
人生不相见,动如参与商.
Spring基本是所有Java学习者绕不开的框架,其对于现代Java的开发具有里程碑式的作用,将java开发者从繁杂的框架和配置中解放出来(至少是部分解放出来)。在github上看到一个微型的spring框架实现项目,觉得很有必要学习一下,谁知道断断续续用了三个月才完全自己实现了一遍,本篇文章对于这个项目的学习做一个总结。
谈到Spring,我们一般会想到它的IOC和AOP特性,也就是上图的Core Containter和AOP以及Aspects部分。Tiny-Spring项目从最简单的IOC容器类开始,实现了Spring的IOC和AOP的基本功能,
先看下最基础的对于bean的定义,以下是最简单的bean定义,只包含了对于bean本身的设置和获取方法:
public class BeanDefinition {
private Object bean;
public BeanDefinition(Object bean){
this.bean = bean;
}
public Object getBean(){
return bean;
}
}
众所周知,Spring使用工厂方法来管理bean,那么我们还需要一个最基础的工厂类:
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管理功能,可以测试一下。
先定义一个pojo类:
public class HelloWorldService {
public void hello(){
System.out.println("Hello World");
}
}
写一个测试方法:
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();
}
}
以上是关于Tiny-Spring项目学习总结的主要内容,如果未能解决你的问题,请参考以下文章