模拟Spring中Bean的加载
最近看了一些关于Spring的书籍,结合网上的相关案列,模拟一下Spring的Bean加载的过程
1 模拟Spring的加载环境
1 添加自定义的相关注解
Component注解
在类上使用, 将类注册到中,并且可以指定名称,默认为类名小写.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value();
}
ComponentScan注解
扫描指定路径, 得到路径下所有的class文件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value() default "";
}
Scope注解
Bean对象的作用域,默认是单例的
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value() default "singleton";
}
BeanDefinition类
Bean对象的定义类,用来定义对象和作用范围的.
public class BeanDefinition {
private Class aClass;
private String scope;
public Class getaClass() {
return aClass;
}
public void setaClass(Class aClass) {
this.aClass = aClass;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}
ApplicationContext类
环境上下文对象,负责添加和获取Bean对象到容器.
public class ApplicationContext {
private ConcurrentHashMap<String, Object> singletonMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public ApplicationContext(Class aClass) {
// 1 获取componentScan注解上的扫描路径
ComponentScan componentScan = (ComponentScan) aClass.getDeclaredAnnotation(ComponentScan.class);
String value = componentScan.value().replace(".", "/");
String path = aClass.getClassLoader().getResource(value).getPath();
// 2 获取路径下所有class文件
List<File> fileList = FileUtils.getFileList(path);
// 3 将注入的Bean对象放到beanDefinitionMap容器中
fileList.forEach(file -> {
// 得到每个文件的路径
String filePath = file.getPath();
// 得到类路径 (indexOf方法包头不包尾)
String classPath = filePath.substring(filePath.indexOf("classes") + 8, filePath.indexOf(".class")).replace("\\", ".");
try {
// 4 将每个Class对象添加到容器中
BeanDefinition beanDefinition = new BeanDefinition();
BeanDefinition beanDefinition = new BeanDefinition();
Class cla = Class.forName(classPath);
if (cla.isAnnotationPresent(Component.class)) {
Component component = (Component) cla.getDeclaredAnnotation(Component.class);
String className = component.value();
beanDefinition.setaClass(cla);
if (cla.isAnnotationPresent(Scope.class)) {
Scope scope = (Scope) cla.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scope.value());
} else {
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(className, beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
);
}
/**
* 根据Bean名称获取对象
*
* @param beanName
* @return
*/
public Object getBean(String beanName) {
Object o = null;
try {
if (beanDefinitionMap.containsKey(beanName)) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
// 多例
if ("prototype".equals(beanDefinition.getScope())) {
o = beanDefinition.getaClass().newInstance();
} else if (singletonMap.containsKey(beanName)) {
// 单例 且容器中已存在
o = singletonMap.get(beanName);
} else {
// 单例 且容器中不存在
o = beanDefinition.getaClass().newInstance();
singletonMap.put(beanName, o);
}
}
} catch (Exception e) {
throw new RuntimeException("找不到相应的 Bean 对象");
}
return o;
}
}
2 添加相关的测试类
ConfigDemo类
给上下文对象使用,获取其注解路径,扫描路径,并注册相关的Bean对象
@ComponentScan("com.cf.service")
public class ConfigDemo {
}
UserService类
用户类接口,供测试使用
package com.cf.service;
public interface UserService {
Integer getUserSum();
}
OrgService类
组织类接口,供测试使用
package com.cf.service;
public interface OrgService {
Integer getOrgSum();
}
UserServiceImpl类
用户接口的实现类,供测试使用
@Component("user")
public class UserServiceImpl implements UserService {
@Override
public Integer getUserSum() {
Integer count = 100;
System.out.println("总共有 " + count + " 个用户");
return count;
}
}
OrgServiceImpl类
组织接口的实现类,供测试使用
@Component("org")
@Scope("prototype")
public class OrgServiceImpl implements OrgService {
@Override
public Integer getOrgSum() {
Integer count = 50;
System.out.println("总共有 " + count + " 个组织");
return count;
}
}
SpringTest类
测试类
public class SpringTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(ConfigDemo.class);
Object user = applicationContext.getBean("user");
Object user2 = applicationContext.getBean("user");
Object org = applicationContext.getBean("org");
Object org2 = applicationContext.getBean("org");
System.out.println(user);
System.out.println(user2);
System.out.println(org);
System.out.println(org2);
}
}
执行结果
/*
com.cf.service.impl.UserServiceImpl@2d98a335
com.cf.service.impl.UserServiceImpl@2d98a335
com.cf.service.impl.OrgServiceImpl@16b98e56
com.cf.service.impl.OrgServiceImpl@7ef20235
*/