Spring 就像是我们写代码的一个管家,可能我们在项目中要创建对象,要写单例多例,要加日志,要加事务等等很多功能点。那这些东西如果能有一个现有的框架那就好了,它就是Spring,它不但实现了以上的功能,并且集成容纳各种其他的开源框架。
自己手写Spring的核心就是springbean的生成。
1:通过包扫描 获取到哪些类需要加载到spring容器中,加载到spring中到底是单例还是多例。
2:单例是从单例池(map)中获取,非单例就是每次getBean的时候重新的创建一个新的对象。
3:因为只有包的名称,所以要通过获取包下面的file来获取file的名称以及全路径,从而通过classload把class信息加载到beanDefinition中
核心代码
public ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
public ConcurrentHashMap<String, Object> singleObjects = new ConcurrentHashMap<String, Object>();
public AnnotationConfigApplicationContext(Class clazz){
//1:通过给的类 获取到需要加载的bean的位置
scan(clazz);
//2.加载到容器
instanceSingleBean();
}
private void instanceSingleBean(){
try {
//1:获取beanDefinitionMap 封装的类信息
for (String beanName : beanDefinitionMap.keySet()){
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if("singleton".equals(beanDefinition.getScope())){
Object bean = doCreateBean(beanDefinition);
singleObjects.put(beanName, bean);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
private Object doCreateBean(BeanDefinition beanDefinition) throws Exception{
Class clazz = beanDefinition.getBeanClass();
Object bean = clazz.getDeclaredConstructor().newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
String beanName = field.getName();
if(field.isAnnotationPresent(Autowried.class)){
Object fieldBean = getBean(beanName);
field.setAccessible(true);
field.set(bean, fieldBean);
}
}
return bean;
}
private void scan(Class clazz) {
//1:获取当前类的注解 找到需要扫描的包的路径
ComponentScan scan = (ComponentScan)clazz.getAnnotation(ComponentScan.class);
String packagePath = scan.value();
//获取当前包下的所有的类
List<Class> packageClass = genBeanClasses(packagePath);
//2:把类封装为BeanDefinition的map
toMap(packageClass);
}
private void toMap(List<Class> packageClass) {
for (Class clazz : packageClass){
if(clazz.isAnnotationPresent(Service.class)){
//通过当前clazz封装BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClass(clazz);
Service service = (Service) clazz.getAnnotation(Service.class);
String beanName = service.value();
if(clazz.isAnnotationPresent(Scope.class)){
Scope scope = (Scope) clazz.getAnnotation(Scope.class);
String scopeValue = scope.value();
if("prototype".equals(scopeValue)){
beanDefinition.setScope("prototype");
}else{
beanDefinition.setScope("singleton");
}
}
beanDefinitionMap.put(beanName, beanDefinition);
}
}
}
/**
* 通过com.mkb.server -> com/mkb/service 再拼接上 类的全路径 得到file文件 通过file文件 获取到文件名 就是 service名称
* 然后通过 classLoader.loadClass(className); 获取到class 集合
*/
private List<Class> genBeanClasses(String packagePath) {
List<Class> beanClasses = new ArrayList<Class>();
ClassLoader classLoader = AnnotationConfigApplicationContext.class.getClassLoader();
packagePath = packagePath.replace(".", "/");
URL resource = classLoader.getResource(packagePath);
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")) {
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\", ".");
try {
Class<?> clazz = classLoader.loadClass(className);
beanClasses.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
return beanClasses;
}
public Object getBean(String beanName) throws Exception{
if(!beanDefinitionMap.containsKey(beanName)){
throw new Exception();
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if("singleton".equals(beanDefinition.getScope())){
return singleObjects.get(beanName);
}else{
return doCreateBean(beanDefinition);
}
}