1、创建maven项目spring20,模拟实现Spring的IOC容器
2、各个配置文件:
web.xml:用于servlet的启动配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
application.properties:配置spring相关信息,主要是扫描包的信息
scanPackage=demo
3、先创建与web相关的5个注解类:
package servlet.annotation;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
String value() default "";
}
package servlet.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
String value() default "";
}
package servlet.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
String value() default "";
}
package servlet.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
String value();
}
package servlet.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value() default "";
}
4、创建核心控制器类DispatcherServlet
package servlet;
import servlet.annotation.Autowired;
import servlet.annotation.Controller;
import servlet.annotation.Service;
import servlet.context.ApplicationContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
//Servlet只是作为mvc的启动入口
public class DispatcherServlet extends HttpServlet {
private final String LOCATION="contextConfigLocation";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
public void init(ServletConfig config) throws ServletException {
ApplicationContext applicationContext=new ApplicationContext(config.getInitParameter(LOCATION));
}
}
5、创建ioc生成类,主要包含这几个类,如下图所示:
package servlet.context.beans;
/**
* 存储配置文件中的信息,相当于保存在内存中的配置
*/
public class BeanDefinition {
private String beanClassName;
private String factoryBeanName;
private boolean lazyInit=false;
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
}
public String getFactoryBeanName() {
return factoryBeanName;
}
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
public boolean isLazyInit() {
return lazyInit;
}
public void setLazyInit(boolean lazyInit) {
this.lazyInit = lazyInit;
}
// public void setBeanClassName(String beanClassName){
//
// }
//
// public String getBeanCLassName(){
// return null;
// }
//
// public void setFactoryBeanName(String factoryBeanName){
//
// }
//
// public String getFactoryBeanName(){
// return null;
// }
//
// public void setLazyInit(boolean lazyInit){
//
// }
//
// public boolean isLazyInit(){
// return false;
// }
}
package servlet.context.beans;
//用于做事件监听
public class BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean,String beanName){
return null;
}
public Object postProcessAfterInitializatioin(Object bean,String beanName){
return null;
}
}
package servlet.context.beans;
public class BeanWrapper {
//还会用到观察者模式
// 支持事件响应,会有一个监听
private BeanPostProcessor beanPostProcessor;
private Object wrapperInstance;
//通过反射new出来的,要把它包装起来
private Object originalInstance;
public BeanWrapper(Object instance) {
this.wrapperInstance = instance;
this.originalInstance = instance;
}
public Object getWrappedInstance() {
return this.wrapperInstance;
}
//返回代理以后的Class
//可能会是$Proxy0
public Class<?> getWrappedClass() {
return this.wrapperInstance.getClass();
}
public BeanPostProcessor getBeanPostProcessor() {
return beanPostProcessor;
}
public void setBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessor = beanPostProcessor;
}
}
package servlet.context.support;
import servlet.context.beans.BeanDefinition;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
//用于对配置文件查找,读取,解析
public class BeanDefinitiionReader {
private Properties config=new Properties();
private List<String> registyBeanClasses=new ArrayList<String>();
//配置文件中用来获取自动扫描的包名的key
private final String SCAN_PACKAGE="scanPackage";
public BeanDefinitiionReader(String ... locations){
//spring中通过reader去查找和定位
InputStream is=this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath:",""));
try {
config.load(is);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(null!=is) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
doScanner(config.getProperty(SCAN_PACKAGE));
}
public List<String> getRegistyBeanClasses(){
return null;
}
public List<String> loadBeanDefinitions(){
return this.registyBeanClasses;
};
//每注册一个className,就返回一个BeanDefinition,自己包装
//BeanDefinition只是为了对配置信息进行包装
public BeanDefinition registerBean(String className){
if(this.registyBeanClasses.contains(className)){
BeanDefinition beanDefinition=new BeanDefinition();
beanDefinition.setBeanClassName(className);
beanDefinition.setFactoryBeanName(toLowerFirstWord(className.substring(className.lastIndexOf(".")+1)));
return beanDefinition;
}
return null;
}
//递归扫描所有相关联的class,保存在一个List中
private void doScanner(String packageName){
URL url=this.getClass().getClassLoader().getResource("/"+packageName.replaceAll("\\.","/"));
File classDir=new File(url.getFile());
for(File file:classDir.listFiles()){
if(file.isDirectory()){
doScanner(packageName+"."+file.getName());
}else {
registyBeanClasses.add(packageName+"."+file.getName().replace(".class",""));
}
}
}
private String toLowerFirstWord(String str){
char[] charArr=str.toCharArray();
charArr[0]+=32;
return String.valueOf(charArr);
}
public Properties getConfig(){
return this.config;
}
}
package servlet.core;
public interface BeanFactory {
Object getBean(String beanName);
}
package servlet.context;
import servlet.annotation.Autowired;
import servlet.annotation.Controller;
import servlet.annotation.Service;
import servlet.context.beans.BeanDefinition;
import servlet.context.beans.BeanPostProcessor;
import servlet.context.beans.BeanWrapper;
import servlet.context.support.BeanDefinitiionReader;
import servlet.core.BeanFactory;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ApplicationContext implements BeanFactory {
private String[] configLocations;
private BeanDefinitiionReader reader;
//用来保存配置信息的map
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
//用来保存注册是单例的容器
private Map<String, Object> beanCacheMap = new HashMap<>();
//用来存储所有的被代理过得对象
private Map<String,BeanWrapper> beanWrapperMap = new ConcurrentHashMap<>();
public ApplicationContext(String... configLocations) {
this.configLocations = configLocations;
refresh();
}
public void refresh() {
//定位
this.reader = new BeanDefinitiionReader(configLocations);
//加载
List<String> beanDefinitions = reader.loadBeanDefinitions();
//注册
doRegistry(beanDefinitions);
//依赖注入,(lazy-init=false,执行依赖注入)
//这里自动调用getBean方法
doAutowired();
System.out.println("IOC注册成功");
}
private void doAutowired(){
for(Map.Entry<String,BeanDefinition> beanDefinitionEntry:beanDefinitionMap.entrySet()){
//如果这个bean不是延迟加载,调用getBean方法进行实例化
if(!beanDefinitionEntry.getValue().isLazyInit()){
String beanName=beanDefinitionEntry.getKey();
getBean(beanName);
}
}
}
//依赖注入
public void populateBean(String bean,Object instance){
Class clazz=instance.getClass();
//对包含Controller.class和包含Service.class的类进行依赖注入
if(clazz.isAnnotationPresent(Controller.class)||clazz.isAnnotationPresent(Service.class)){
Field[] fields=clazz.getDeclaredFields();
for (int i = 0; i <fields.length; i++) {
Field field=fields[i];
//如果字段内不包含autowire注释,跳过该字段继续循环
if(!field.isAnnotationPresent(Autowired.class)){
continue;
}
Autowired autowired=field.getAnnotation(Autowired.class);
//获取autowired注解的值
String beanName=autowired.value().trim();
//如果注解值为空,使用默认注解
if("".equals(beanName)){
beanName=field.getType().getName();
}
Object object=beanWrapperMap.get(beanName).getWrappedInstance();
field.setAccessible(true);
try {
field.set(instance,object);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
// 真正的将beanDefiniton注册到beanDefinitionMap
private void doRegistry(List<String> beanDefinitions) {
//beanName有三种情况
//1、默认首字母小写
//2、自定义名字
//3、接口注入
try {
for (String className : beanDefinitions) {
Class<?> beanClass = Class.forName(className);
if (beanClass.isInterface()) {
continue;
}
BeanDefinition beanDefinition = reader.registerBean(className);
if(beanDefinition!=null){
this.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);
}
Class<?>[] interfaces=beanClass.getInterfaces();
for (Class clazz:interfaces
) {
this.beanDefinitionMap.put(clazz.getName(),beanDefinition);
}
//到这里为止,容器初始化完毕
}
} catch (Exception e) {
e.printStackTrace();
}
}
//依赖注入从这里开始,通过读取BeanDefinition中的信息,
//然后,通过反射机制创建一个实例,并返回
//Spring的做法是,不会把最原始的对象放出去,会用一个BeanWrapper来进行一次包装
//装饰器模式,
//1、保留原来的OOP关系
//2、我需要对他进行扩展和增强
@Override
public Object getBean(String beanName) {
BeanDefinition beanDefinition=this.beanDefinitionMap.get(beanName);
String className=beanDefinition.getBeanClassName();
try{
//生成通知事件
BeanPostProcessor beanPostProcessor=new BeanPostProcessor();
Object instance=instantionBean(beanDefinition);
if(null==instance){
return null;
}
//实例初始化以前调用一次
beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
BeanWrapper beanWrapper=new BeanWrapper(instance);
beanWrapper.setBeanPostProcessor(beanPostProcessor);
this.beanWrapperMap.put(beanName,beanWrapper);
//实例初始化以后调用一次
beanPostProcessor.postProcessAfterInitializatioin(instance,beanName);
populateBean(beanName,instance);
//通过这样一调用,相当于给自己留下了可操作空间
return this.beanWrapperMap.get(beanName).getWrappedInstance();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
//传一个beanDefinition,返回一个instance
private Object instantionBean(BeanDefinition beanDefinition){
Object instance=null;
String className=beanDefinition.getBeanClassName();
try {
//根据class才能确定一个类是否有实例
if(this.beanCacheMap.containsKey(className)){
instance=this.beanCacheMap.get(className);
}else{
Class clazz=Class.forName(className);
instance=clazz.newInstance();
beanCacheMap.put(className,instance);
}
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
}
6、测试,构建controller层和service层:
package demo.controller;
import demo.service.IService;
import servlet.annotation.Autowired;
import servlet.annotation.Controller;
import servlet.annotation.RequestMapping;
import servlet.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class DemoController {
@Autowired
IService iService;
@RequestMapping("/getInfo")
public void getInfo(@RequestParam("param") String param){
iService.add();
}
@RequestMapping("/doTest")
public void test1(HttpServletRequest request, HttpServletResponse response,
@RequestParam("param") String param){
System.out.println(param);
try {
response.getWriter().write( "doTest method success! param:"+param);
} catch (IOException e) {
e.printStackTrace();
}
}
@RequestMapping("/doTest2")
public void test2(HttpServletRequest request, HttpServletResponse response){
try {
response.getWriter().println("doTest2 method success!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
package demo.service;
import servlet.annotation.Service;
public interface IService {
public void add();
}
package demo.service.impl;
import demo.service.IService;
import servlet.annotation.Service;
@Service
public class IServiceImpl implements IService {
@Override
public void add() {
System.out.println("新增一条数据");
}
}
启动项目结果如下图,注册成功!