实现简单的spring容器:ApplicationContext
思路+实现:
Beanfinition:用来定义类是单例bean还是prototype
*/
package com.spring;
/**
* Beanfinition:用来定义类是单例bean还是prototype
*/
public class Beanfinition {
private Class clazz;
private String scope;
public Beanfinition() {
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}
ComponentScan:定义要被spring扫描的包
/**
* 定义要扫描的包
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value();
}
Component:定义实体类
/**
* 定义实体类
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
Scope:定义是单例bean还是原型bean
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value();
}
ApplicationContext:spring容器
package com.spring;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* spring容器
*/
public class KikiApplicationContext {
private Class configClass;
/**
* 单例池 用来存储单例对象
*/
private ConcurrentHashMap<String,Object> singletonObjects=new ConcurrentHashMap<>();
private ConcurrentHashMap<String,Beanfinition > beanDefinitionMap=new ConcurrentHashMap<>(); //beanDefinitionMap 储存类的类型是单例bean还是prototype bean
public KikiApplicationContext(Class configClass){
this.configClass=configClass;
//componentScan注解->获取扫描路径->扫描->beanDefinition->beanDefinitionMap
scan(configClass);
for (Map.Entry<String,Beanfinition> entry:beanDefinitionMap.entrySet()){
String beanName = entry.getKey();
Beanfinition beanfinition = beanDefinitionMap.get(beanName);
if(beanfinition.getScope().equals("singleton")){
//单例bean 直接创建bean
Object bean= createBean(beanfinition);
//将创建出来的单例bean放到单例池中
singletonObjects.put(beanName,bean);
}
}
}
public Object createBean(Beanfinition beanfinition) {
Class clazz = beanfinition.getClazz();
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
/**
* 扫描
* @param configClass
*/
private void scan(Class configClass) {
//解析配置类
//1.拿到ComponentScan注解
ComponentScan componentScanAnnotatio = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
//2.获取扫描路径
String path = componentScanAnnotatio.value();
//3.扫描 获取application类加载器 根据类加载器获取指定目录下的class,遍历class
//3.1类加载器 Bootstrap->jre/lib Ext->jre/ext/lib App->classpath
ClassLoader classLoader = KikiApplicationContext.class.getClassLoader();
URL resource = classLoader.getResource(path.replace(".","/"));
File file = new File(resource.getFile());
if(file.isDirectory()){
// 获取扫描文件下的所有文件
File[] files = file.listFiles();
for (File f : files) {
String fileName = f.getAbsolutePath();///Users/kiki/workspace/learn/source/Spring-kiki/target/classes/com/kiki/service/UserService.class
if (fileName.endsWith(".class")){
//3.2 遍历class文件
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
//3.3获取全限定名
className=className.replace("/",".");
try {
//根据全限定名获取class
Class<?> clazz = classLoader.loadClass(className);//com.kiki.service.Uservice
if(clazz.isAnnotationPresent(Component.class)){ //表示当前是一个bean //被Component修饰说明需要在加载时初始化进spring容器中
//3.4判断当前对象是单例bean还是prototype的bean ->Beanfinition
Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
String beanName = componentAnnotation.value(); //beanName
Beanfinition beanfinition = new Beanfinition();
if(clazz.isAnnotationPresent(Scope.class)){
//包含scope注解 获取属性
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
beanfinition.setScope(scopeAnnotation.value());
}else{
//单例bean
beanfinition.setScope("singleton");
}
beanfinition.setClazz(clazz);
beanDefinitionMap.put(beanName,beanfinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
public Object getBean(String beanName){
//根据名字找到对应的类
if(beanDefinitionMap.containsKey(beanName)){
//判断类是单例bean还是prototype的bean
Beanfinition beanfinition = beanDefinitionMap.get(beanName);
if(beanfinition.getScope().equals("singleton")){
//单例bean 直接从单例池中取出
return singletonObjects.get(beanName);
}else{
//原型bean
//创建bean对象
return createBean(beanfinition);
}
}else {
//不存在对应的bean
throw new NullPointerException();
}
}
}
测试类
AppConfig:声明被管理的包
@ComponentScan("com.kiki.service")
public class AppConfig {
}
UserService :测试类
package com.kiki.service;
import com.spring.Component;
import com.spring.Scope;
@Scope("singleton") //原型bean
@Component("userService")
public class UserService {
public void add(){
System.out.println("this is userservice add method");
}
}
测试类
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
KikiApplicationContext applicationContext = new KikiApplicationContext(AppConfig.class);
System.out.println(applicationContext.getBean("userService"));
System.out.println(applicationContext.getBean("userService"));
System.out.println(applicationContext.getBean("userService"));
}
}