前言:加深对spring的理解,把spring ioc的大致流程抽出来,自己动手撸一个简洁版的
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.fandaygroupId>
<artifactId>springartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.0.1version>
<scope>providedscope>
dependency>
dependencies>
project>
项目结构:
编写接口定义
package com.fanday.ioc;
import java.util.Map;
public interface ApplicationContext {
/**
* 根据id获取bean
* @param id
* @return
*/
Object getBean(String id);
/**
* 根据id获取特定类型的bean,完成强转
* @param id
* @param clazz
* @param
* @return
*/
T getBean(String id,Class clazz);
/**
* 获取工厂内的所有bean集合
* @return
*/
Map getBeans();
}
package com.fanday.ioc;
import com.fanday.ioc.support.BeanDefinition;
import java.util.List;
public interface BeanRegister {
/**
* 向工厂内注册BeanDefinition
* @param bds
*/
void registBeanDefinition(List bds);
/**
* 向工厂内注册bean实例对象
* @param id
* @param instance
*/
void registInstanceMapping(String id,Object instance);
}
support包主要是一些默认的工厂实现,annotation包是一些需要的注解
package com.fanday.ioc.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)//运行时注解
@Target(ElementType.TYPE)//作用在类上面
@Documented
public @interface Controller {
String value() default "";
}
package com.fanday.ioc.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Component {
String value() default "";
}
package com.fanday.ioc.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//作用在字段上面
@Documented
public @interface Autowire {
String value() default "";
}
package com.fanday.ioc.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})//作用在类和方法 仿照springmvc的套路来
@Documented
public @interface RequestMapping {
String value() default "";
}
package com.fanday.ioc.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)//作用在方法的参数上面
@Documented
public @interface RequestParam {
String value() default "";
}
resources下新建一个applicationContext.properties文件用于配置,容器启动时要扫描的包
scanPackage=com.fanday.demo
AnnotationApplicationContext 容器的具体实现
package com.fanday.ioc.support;
import com.fanday.ioc.ApplicationContext;
import com.fanday.ioc.BeanRegister;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
public class AnnotationApplicationContext implements ApplicationContext,BeanRegister {
private Map instanceMapping = new ConcurrentHashMap();
//保存所有bean的信息,主要包含bean的类型 id等信息
private List beanDefinitions = new ArrayList();
//配置文件的config,这里为了简单我们使用properties文件
private Properties config = new Properties();
public AnnotationApplicationContext(String location){
InputStream is = null;
try{
//1、定位
is = this.getClass().getClassLoader().getResourceAsStream(location);
//2、载入
config.load(is);
//3、注册
register();
//4、实例化
createBean();
//5、注入
populate();
}catch(Exception e){
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 调用具体委派的注入类进行注入
*/
private void populate() {
Populator populator = new Populator();
populator.populate(instanceMapping);
}
/**
* 调用具体的创建对象创建bean
*/
private void createBean() {
BeanCreater creater = new BeanCreater(this);
creater.create(beanDefinitions);
}
/**
* 调用具体的注册对象注册bean信息
*/
private void register() {
BeanDefinitionParser parser = new BeanDefinitionParser(this);
parser.parse(config);
}
public Object getBean(String id) {
return instanceMapping.get(id);
}
public Properties getConfig() {
return this.config;
}
public T getBean(String id, Class clazz) {
return (T)instanceMapping.get(id);
}
public Map getBeans() {
return instanceMapping;
}
public void registBeanDefinition(List bds) {
beanDefinitions.addAll(bds);
}
public void registInstanceMapping(String id, Object instance) {
instanceMapping.put(id,instance);
}
}
BeanDefinitionParser完成扫描包下bean信息的解析注册
package com.fanday.ioc.support;
import com.fanday.ioc.BeanRegister;
import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Properties;
public class BeanDefinitionParser {
//配置的扫描包的key
public static final String SCAN_PACKAGE = "scanPackage";
//容器注册对象
private BeanRegister register;
public BeanDefinitionParser(BeanRegister register){
this.register = register;
}
public void parse(Properties properties){
//获取要扫描的包
String packageName = properties.getProperty(SCAN_PACKAGE);
//执行注册
doRegister(packageName);
}
private void doRegister(String packageName) {
//获取此包名下的绝对路径
URL url = getClass().getClassLoader().getResource("./"+packageName.replaceAll("\\.","/"));
File dir = new File(url.getFile());
//循环遍历 递归找到所有的java文件
for (File file:dir.listFiles()){
if(file.isDirectory()){
//文件夹-->递归继续执行
doRegister(packageName+"."+file.getName());
}else {
//处理文件名来获取类名 运行时获取到的是class文件
String className = packageName+"."+file.getName().replaceAll(".class","").trim();
//调用BeanDefinitionGenerator.generate(className)方法,来处理
//1.类带有容器要处理的注解,则解析id生成BeanDefinition集合返回
//2.不带有需要处理的注解 直接返回null
List definitions = BeanDefinitionGenerator.generate(className);
if(definitions == null)continue;
//调用容器的注册方法来完成bean信息的注册
this.register.registBeanDefinition(definitions);
}
}
}
}
BeanDefinitionGenerator根据具体的类名来完成BeanDefinition的生成
package com.fanday.ioc.support;
import com.fanday.ioc.annotation.Component;
import com.fanday.ioc.annotation.Controller;
import java.util.ArrayList;
import java.util.List;
public class BeanDefinitionGenerator {
public static List generate(String className){
try {
Class clazz = Class.forName(className);
String[] ids = generateIds(clazz);
if(ids==null)return null;
List list = new ArrayList();
for (String id:ids){
list.add(new BeanDefinition(id,clazz));
}
return list;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* 生成id数组
* 1.带有@Controller 注解但是注解value没给值,@Controller一般没有
* 接口定义,用类的全名作为id返回ids长度为1
* 2.@Component 没有value 获取所有的实现的接口,接口名为id,返货ids数组
* 长度是实现的接口个数
* 3.@Component 有value 返回id=value
* 4.不带容器要实例化的注解 null
*/
private static String[] generateIds(Class clazz) {
String[] ids = null;
if (clazz.isAnnotationPresent(Controller.class)) {
ids = new String[]{clazz.getName()};
} else if (clazz.isAnnotationPresent(Component.class)) {
Component component = (Component) clazz.getAnnotation(Component.class);
String value = component.value();
if (!"".equals(value)) {
ids = new String[]{value};
} else {
Class>[] interfaces = clazz.getInterfaces();
ids = new String[interfaces.length];
//如果这个类实现了接口,就用接口的类型作为id
for (int i = 0; i < interfaces.length; i++){
ids[i] = interfaces[i].getName();
}
return ids;
}
}
return ids;
}
}
package com.fanday.ioc.support;
public class BeanDefinition{
private String id;
private Class clazz;
public BeanDefinition(String id, Class clazz){
this.id = id;
this.clazz = clazz;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
public Object getInstance(){
try {
return clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
BeanCreater比较简单,创建bean并且添加到容器工厂
package com.fanday.ioc.support;
import com.fanday.ioc.BeanRegister;
import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Properties;
public class BeanCreater {
private BeanRegister register;
public BeanCreater(BeanRegister register){
this.register = register;
}
public void create(List bds){
for (BeanDefinition bd:bds){
doCreate(bd);
}
}
private void doCreate(BeanDefinition bd) {
Object instance = bd.getInstance();
this.register.registInstanceMapping(bd.getId(),instance);
}
}
bean都初始化完成了,接下来进行bean之间的依赖注入
package com.fanday.ioc.support;
import java.lang.reflect.Field;
import java.util.Map;
import com.fanday.ioc.annotation.Autowire;
public class Populator {
public Populator(){
}
public void populate(Map instanceMapping){
//首先要判断ioc容器中有没有东西
if(instanceMapping.isEmpty())return;
//循环遍历每一个容器中得对象
for (Map.Entry entry:instanceMapping.entrySet()){
//获取对象的字段
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field:fields){
if(!field.isAnnotationPresent(Autowire.class))continue;
Autowire autowire = field.getAnnotation(Autowire.class);
//后去字段要注入的id value 为空则按类名 接口名自动注入
String id = autowire.value();
if("".equals(id))id = field.getType().getName();
field.setAccessible(true);
try {
//反射注入
field.set(entry.getValue(),instanceMapping.get(id));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
至此 ioc的整个流程大致完成,我们来编写测试
ok,ioc容器实现已基本完成,下次一起来撸mvc