您的位置:首页 > 编程语言 > Java开发

自己实现spring核心功能 二

2019-08-17 18:00 1571 查看

前言

上一篇我们讲了spring的一些特点并且分析了需要实现哪些功能,已经把准备工作都做完了,这一篇我们开始实现具体功能。

容器加载过程

 我们知道,在spring中refesh()方法做了很多初始化的工作,它几乎涵盖了spring的核心流程

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//刷新之前的准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置
prepareRefresh();
//由子类去刷新BeanFactory(如果还没创建则创建),并将BeanFactory返回
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备BeanFactory以供ApplicationContext使用
prepareBeanFactory(beanFactory);
try {
//子类可通过格式此方法来对BeanFactory进行修改
postProcessBeanFactory(beanFactory);
//实例化并调用所有注册的BeanFactoryPostProcessor对象
invokeBeanFactoryPostProcessors(beanFactory);
//实例化并调用所有注册的BeanPostProcessor对象
registerBeanPostProcessors(beanFactory);
//初始化MessageSource
initMessageSource();
//初始化事件广播器
initApplicationEventMulticaster();
//子类覆盖此方法在刷新过程做额外工作
onRefresh();
//注册应用监听器ApplicationListener
registerListeners();
//实例化所有non-lazy-init bean
finishBeanFactoryInitialization(beanFactory);
//刷新完成工作,包括初始化LifecycleProcessor,发布刷新完成事件等
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}

 做的东西比较复杂,而我们实现做些基本的就好了。

 我们在CJDispatcherServlet 类的init方法中,实现如下业务逻辑,就能将spring功能给初始化了,就可以使用依赖注入了

@Override
public void init(ServletConfig config) {
//加载配置

//获取要扫描的包地址

//扫描要加载的类

//实例化要加载的类

//加载依赖注入,给属性赋值

//加载映射地址

}

 

加载配置

String contextConfigLocation = config.getInitParameter("contextConfigLocation");

loadConfig(contextConfigLocation);

这里会获取到web.xml中init-param节点中的值

public interface IHomeService {
String sayHi();
String getName(Integer id,String no);
String getRequestBody(Integer id, String no, GetUserInfo userInfo);
}

public interface IStudentService {
String sayHi();
}
View Code  

实现类:
@JCService
public class StudentService  implements IStudentService{
@Override
public String sayHi(){
return "Hello world!";
}
}
View Code
@JCService
public class HomeService  implements IHomeService{

@JCAutoWrited
StudentService studentService;
@Override
public String sayHi() {
return   studentService.sayHi();
}

@Override
public String getName(Integer id,String no) {
return "SB0000"+id;
}

@Override
public String getRequestBody(Integer id, String no, GetUserInfo userInfo) {
return "userName="+userInfo.getName()+" no="+no;
}
}
View Code

依赖实体:

public class GetUserInfo {
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public BigDecimal getGrowthValue() {
return growthValue;
}

public void setGrowthValue(BigDecimal growthValue) {
this.growthValue = growthValue;
}

private String name;
private Integer age;
private BigDecimal growthValue;

}
View Code

 



加载依赖注入,给属性赋值

//加载依赖注入,给属性赋值
doAutoWrited();

  现在我们实现依赖注入,需要定义一个无参的方法doAutoWrite

 

void doAutoWrited() {
for (Map.Entry<String, Object> obj : ioc.entrySet()) {
try {
for (Field field : obj.getValue().getClass().getDeclaredFields()) {
if (!field.isAnnotationPresent(JCAutoWrited.class)) {
continue;
}
JCAutoWrited autoWrited = field.getAnnotation(JCAutoWrited.class);
String beanName = autoWrited.value();
if ("".equals(beanName)) {
beanName = field.getType().getSimpleName();
}

field.setAccessible(true);

field.set(obj.getValue(), ioc.get(firstLowerCase(beanName)));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}

}

}

 这个方法是通过循环ioc里面的实体,反射找出字段,看看是否有需要注入的标记JCAutoWrited,如果加了标记,就反射给字段赋值,类型从ioc容器中获取

 

 加载映射地址 

//加载映射地址
doRequestMapping();

 

 映射地址的作用是根据请求的url匹配method方法

void doRequestMapping() {
if (ioc.isEmpty()) {
return;
}
for (Map.Entry<String, Object> obj : ioc.entrySet()) {
if (!obj.getValue().getClass().isAnnotationPresent(JCController.class)) {
continue;
}
Method[] methods = obj.getValue().getClass().getMethods();
for (Method method : methods) {
if (!method.isAnnotationPresent(JCRequestMapping.class)) {
continue;
}
String baseUrl = "";
if (obj.getValue().getClass().isAnnotationPresent(JCRequestMapping.class)) {
baseUrl = obj.getValue().getClass().getAnnotation(JCRequestMapping.class).value();
}
JCRequestMapping jcRequestMapping = method.getAnnotation(JCRequestMapping.class);
if ("".equals(jcRequestMapping.value())) {
continue;
}
String url = (baseUrl + "/" + jcRequestMapping.value()).replaceAll("/+", "/");
urlMapping.put(url, method);
System.out.println(url);
}
}
}

这里其实就是根据对象反射获取到JCRequestMapping上面的value值

@JCRequestMapping("/sayHi")

 取到的就是/sayHi

另外注意的是:黄色部分使用的变量是一个hashMap,在类上半部分定义的

private Map<String, Method> urlMapping = new HashMap<>();

这里面存的是 url 和对应的method对象。后面处理请求的时候要使用到的。


结尾

容器的初始化到这里就结束了,一共使用了4个容器来存放相关对象,后续servlet处理请求的时候会用到它们。

下一篇,将会继续完善它,通过请求来验证是否可以达到预期效果。另外会实现参数绑定,能处理各类请求并响应。

完整代码地址

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: