本篇文章为你整理了手写模拟spring底层原理(手写springboot)的详细内容,包含有spring框架 手写springboot 手写spring框架源码 手写模拟app 手写模拟spring底层原理,希望能帮助你了解 手写模拟spring底层原理。
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
项目基本结构
1.创建@ComponentScan注解,定义包扫描路劲
//定义扫描路劲
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value() default "";
2.创建@Component注解,向spring容器注册bean
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
3.创建AppConfig配置类,定义包扫描路径。
//配置类
@ComponentScan("com.test.service")
public class AppConfig {
4.创建OrderService和UserService类。
@Component("userService")
@Scope("prototype")
public class UserService {
public void test(){
System.out.println("useService");
//存储BeanDefinition对象
private Map String,BeanDefinition beanDefinitionMap=new HashMap ();
//单例池map,存储单例bean对象
Map String,Object singletonObject=new HashMap ();
public TestApplicationContext(Class configClass) {
this.configClass = configClass;
public Object getBean(String name){
return null;
6.从容器获取bean对象。
public class Test {
public static void main(String[] args) {
//创建conext容器,创建单例bean,Appconfig构造方法中完成
TestApplicationContext applicationContext = new TestApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("UserService");
至此大体框架已经完成,接下来完成如何扫描,创建bean对象,bean初始化前,初始化,初始化后的相关实现等等
在TestApplicationContext 的构造方法中扫描AppConfig定义的扫描路径,扫描定义的bean。
public TestApplicationContext(Class configClass) {
this.configClass = configClass;
//扫描
scan(configClass);
private void scan(Class configClass) {
//判断当前类上是否有ComponentScan注解
if (configClass.isAnnotationPresent(ComponentScan.class)){
ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
String path = componentScanAnnotation.value();
path=path.replace(".","/"); // com/test/service
//获取target包下的class文件取出,解析注解,通过Appclassloader类加载器获取
ClassLoader classLoader = TestApplicationContext.class.getClassLoader();
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
//取出目录下的文件,遍历
if (file.isDirectory()){
for (File f : file.listFiles()) {
String absolutePath = f.getAbsolutePath();
//path(C:\Users\cchuang4\IdeaProjects\springDemo\target\classes\com\test\service\OrderService.class)转换成com.test.service
absolutePath=absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
absolutePath=absolutePath.replace("\\",".");
try {
//判断class文件是否有@Component注解
//将class文件加载进来成为class对象
Class ? clazz = classLoader.loadClass(absolutePath);
if (clazz.isAnnotationPresent(Component.class)){
//获取beanname
Component componentAnnotation = clazz.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
//创建BeanDefinition对象
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(clazz);
//Bean是否为单例或原型
if (clazz.isAnnotationPresent(Scope.class)){
Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
String value = scopeAnnotation.value();
beanDefinition.setScope(value);
}else {
//单例
beanDefinition.setScope("singleton");
//将bean的相关元信息存入beandefinitionMap
beanDefinitionMap.put(beanName,beanDefinition);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
在TestApplicationContext容器加载的时候,如何去获取bean的一些元信息等,需要定义对一个bean元信息的描述,比如bean的class,bean的作用域,bean的Order等信息,在Spring生成bean的时候需要依赖于BeanDefinfition。
创建BeanDefinfition
package com.spring;
public class BeanDefinition {
//类型
private Class type;
//作用域
private String scope;
//是否懒加载
private boolean isLazy;
public Class getType() {
return type;
public void setType(Class type) {
this.type = type;
public String getScope() {
return scope;
public void setScope(String scope) {
this.scope = scope;
public boolean isLazy() {
return isLazy;
public void setLazy(boolean lazy) {
isLazy = lazy;
单例bean的获取去遍历beanDefinitionMap,找出所有的单例bean,并存入单例池map中,在getBean()时呢能够快速的获取单例bean。TestApplicationContext的构造方法:
public TestApplicationContext(Class configClass) {
this.configClass = configClass;
//扫描
scan(configClass);
//遍历map
for (Map.Entry String, BeanDefinition entry : beanDefinitionMap.entrySet()) {
String beanName= entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (beanDefinition.getScope().equals("singleton")){
//获取单例bean
Object bean = createBean(beanName, beanDefinition);
//将单例bean存进单例池的map中,在getBean()时直接拿取
singletonObject.put(beanName,bean);
通过getBean()方法去获取bean,先通过beanDefinitionMap获取beanDefinition,再去判断是单例/原型bean,如果是单例bean,直接从单例池singletonObject中获取。
public Object getBean(String beanName){
//判断是否有这个bean
if (!beanDefinitionMap.containsKey(beanName)){
throw new NullPointerException();
}else {
//获取beanDefinition对象
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//判断单例/原型bean
if (beanDefinition.getScope().equals("singleton")){
//从单例池中直接获取
Object singletonBean = singletonObject.get(beanName);
return singletonBean;
}else {
//原型
Object prototypeBean = createBean(beanName, beanDefinition);
return prototypeBean;
createBean()方法,创建bean对象
Object createBean(String beanName,BeanDefinition beanDefinition){
Class clazz = beanDefinition.getType();
Object instance = null;
try {
instance = clazz.getConstructor().newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
return instance;
至此已经支持单例bean和原型bean的获取。
!!!测试运行Test类
1.当userService的@Scope("singleton")时:
1.当userService的@Scope("prototype")时:
此时@Component注解上要指定beanName,否则会NPE,如何获取默认的bean的名字?
//设置默认beanName
if (beanName.equals("")){
beanName= Introspector.decapitalize(clazz.getSimpleName());
@AutoWire依赖注入的实现
创建Autowired注解,并在Userservice里添加OrderService属性。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
String value() default "";
UserService.class
@Component("userService")
@Scope("prototype")
public class UserService {
@Autowired
private OrderService orderService;
public void test(){
System.out.println(orderService);
在创建bean时进行依赖注入,先根据type,再根据name去容器中找。createBean():
Object createBean(String beanName,BeanDefinition beanDefinition){
Class clazz = beanDefinition.getType();
Object instance = null;
try {
instance = clazz.getConstructor().newInstance();
//依赖注入
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)){
field.setAccessible(true);
//根据type去单例池或beanDefinitionMap中去找
//...省略
//根据beanName去找
field.set(instance,getBean(beanName));
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
return instance;
此时若先扫描到UserService,然后去创建UserService这个bean,然后在上面依赖注入的field.set(instance,getBean(beanName))时,此时OrderService单例池中还没有创建这个bean,依赖注入就会出问题。此时在创建bean时再去判断bean是否存在,不存在则再生成。
public Object getBean(String beanName){
//判断是否有这个bean
if (!beanDefinitionMap.containsKey(beanName)){
throw new NullPointerException();
}else {
//获取beanDefinition对象
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//判断单例/原型bean
if (beanDefinition.getScope().equals("singleton")){
//从单例池中直接获取
Object singletonBean = singletonObject.get(beanName);
//若此时对应的bean还没有创建,如在依赖注入时
if (singletonBean==null){
singletonBean=createBean(beanName,beanDefinition);
singletonObject.put(beanName,singletonBean);
return singletonBean;
}else {
//原型
Object prototypeBean = createBean(beanName, beanDefinition);
return prototypeBean;
测试,输出UserService里的OrderService对象:
此时依赖注入已经完成
初始化(InitializingBean接口)
创建InitializingBean接口
public interface InitializingBean{
void afterPropertiesSet() throws Exception;
UserService.class
@Component("userService")
@Scope("prototype")
public class UserService implements InitializingBean {
@Autowired
private OrderService orderService;
public void test(){
System.out.println(orderService);
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
此时在UserService加载时afterPropertiesSet不能自动调到。
在createBean()之后判断当前实例是否实现了InitializingBean 接口,实现了则调用afterPropertiesSet方法。
//调用实现了InitializingBean的afterPropertiesSet方法
if (instance instanceof InitializingBean){
((InitializingBean)instance).afterPropertiesSet();
BeanPostProcessor的实现
该接口也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。
default Object postProcessBeforeInitialization(Object bean, String beanName){
return bean;
default Object postProcessAfterInitialization(Object bean, String beanName){
return bean;
创建自己的类,去实现BeanPostProcessor接口,在类上加上@Component(自定义注解),以便被spring托管扫描到。在包扫描(scan()方法)时,会判断如果当前类上有@Component注解,然后会判断是否实现了BeanPostProcessor注解,
此时的bean的后置处理器会针对所有bean,若想针对其中一个bean,则需自己写处理逻辑。
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println(beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
创建在扫描时扫描到的那些实现了BeanPostProcessor接口的对象的list集合。
//存放BeanPostProcessor对象
List BeanPostProcessor beanPostProcessorList=new ArrayList ();
在scan时判断扫描到的那些bean是否实现了BeanPostProcessor接口,实现了则加入list集合中。
if (clazz.isAnnotationPresent(Component.class)){
//判断类是否实现了BeanPostProcessor接口
if (BeanPostProcessor.class.isAssignableFrom(clazz)){
//获得BeanPostProcessor的实例
BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
//将BeanPostProcessor对象存入list(LinkList)
beanPostProcessorList.add(instance);
......
在createBean()时,在调用了实现InitializingBean的afterPropertiesSet()方法之后,再去调用BeanPostProcessor接口的方法。
//调用初始化后方法
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
此时BeanPostProcessor 的postProcessAfterInitialization方法返回值再次赋值给instance对象,基于这一原理可以实现AOP功能,在postProcessAfterInitialization方法里去实现一些切面的逻辑,以及可以在bean初始化前,初始化后去做一些其他的事情,如自定义注解给字段设置默认值等等。
以上就是手写模拟spring底层原理(手写springboot)的详细内容,想要了解更多 手写模拟spring底层原理的内容,请持续关注盛行IT软件开发工作室。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。