模拟实现Spring的@Autowired,@Bean,@Component注解
- 注解
@Autowired
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}
@Bean
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Bean {
}
@Component
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value();
}
@ComponentScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value();
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value();
}
- BeanDefinition实体
public class BeanDefinition {
//Spring容器管理的对象的Class
private Class clazz;
//singleton or prototype
private String scope;
public BeanDefinition() {
}
public BeanDefinition(Class clazz, String scope) {
this.clazz = clazz;
this.scope = scope;
}
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;
}
}
- ApplicationContext
属性
public class ApplicationContext {
//配置类
public Class configClass;
//缓存单例的对象
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
//缓存包含Bean信息的BeanDefinition对象
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
}
构造方法
- 扫描带有@ComponentScan和@Bean注解的配置类,生成BeanDefinition对象并缓存到beanDefinitionMap里
private void scan(Class configClass) {
//用来保存类的全限类名
List<String> list = new ArrayList<>();
ClassLoader classLoader = ApplicationContext.class.getClassLoader();
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScanAnnotation = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
//获取@ComponentScan注解里指定扫描的包名
String path = componentScanAnnotation.value();
//包名 例如com.jxz.annotation 替换成 com/jxz/annotation
String realPath = path.replace(".", "/");
URL resource = classLoader.getResource(realPath);
File file = new File(resource.getFile());
//递归指定包及子包里的所有以.class结尾的全限类名 保存到list里
getClassNames(file, list);
/*
private void getClassNames(File file, List<String> classNames) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
if (f.isDirectory()) {
getClassNames(f, classNames);
}
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")) {
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\", ".");
classNames.add(className);
}
}
}
}
*/
} else {
throw new RuntimeException("找不到指定配置信息");
}
list.stream().forEach(className -> {
try {
//获取每个类的Class对象
Class<?> clazz = classLoader.loadClass(className);
//判断是否有Component注解
if (clazz.isAnnotationPresent(Component.class)) {
Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
String beanName = componentAnnotation.value();
//创建BeanDefinition对象
BeanDefinition beanDefinition = new BeanDefinition();
//设置clazz属性
beanDefinition.setClazz(clazz);
//如果有@Scope注解
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
String scope = scopeAnnotation.value();
if (!"singleton".equals(scope) && !"prototype".equals(scope)) {
throw new RuntimeException("不支持的Scope类型");
}
beanDefinition.setScope(scope);
} else {
//默认为单例
beanDefinition.setScope("singleton");
}
//缓存
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
}
- 缓存带有@Bean注解方法返回的对象到singletonObjects里
Method[] methods = configClass.getDeclaredMethods();
try {
Object o = configClass.newInstance();
for (Method method : methods){
//遍历获取到的所有方法判断是否有@Bean注解
if (method.isAnnotationPresent(Bean.class)){
method.setAccessible(true);
//得到return的对象
Object instance = method.invoke(o);
//beanName默认为方法名
String beanName = method.getName();
//缓存调用方法返回的对象
singletonObjects.put(beanName, instance);
Class<?> clazz = method.getReturnType();
//缓存BeanDefinition对象
BeanDefinition beanDefinition = new BeanDefinition(clazz, "singleton");
beanDefinitionMap.put(beanName, beanDefinition);
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
- 遍历beanDefinitionMap生成Scope为singleton的单例对象,缓存到singletonObject里
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if ("singleton".equals(beanDefinition.getScope())) {
Object bean = null;
try {
bean = createBean(beanName, beanDefinition);
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
singletonObjects.put(beanName, bean);
}
}
- createBean方法
private Object createBean(String beanName, BeanDefinition beanDefinition) throws IllegalAccessException, InstantiationException {
//如果singletonObjects中已经存在则直接返回
//防止重复生成@Bean注解的对象或依赖的对象
Object o = singletonObjects.get(beanName);
if (null != o && "singleton".equals(beanDefinition.getScope())){
return o;
}
Class clazz = beanDefinition.getClazz();
Object instance = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
//如果属性上有@Autowired注解
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
//以 byName注入 getBean方法判断对象scope类型并返回
//getBean方法写到下面了
Object bean = getBean(field.getName());
if (bean == null) {
//代码进到这里说明注入的对象还没有创建或没有此类型的BeanDifinition对象
BeanDefinition beanD = beanDefinitionMap.get(field.getName());
//查看是否存在BeanDefinition对象
if (null != beanD){
//递归调用自己优先创建要注入的对象
bean = createBean(field.getName(), beanD);
if ("singleton".equals(beanD.getScope())){
//缓存到singletonObjects防止单例对象重复生成
//下次走到这里会被上面的if语句ruturn掉
singletonObjects.put(field.getName(), bean);
}
}else {
//没有抛异常
throw new RuntimeException("Can't Autowired " + field.getName());
}
}
field.set(instance, bean);
}
}
return instance;
}
- getBean方法
public Object getBean(String beanName) {
if (beanDefinitionMap.containsKey(beanName)) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//如果是单例的直接从缓存里取
if ("singleton".equals(beanDefinition.getScope())) {
Object o = singletonObjects.get(beanName);
return o;
}
//如果不是单例,使用createBean方法
if ("prototype".equals(beanDefinition.getScope())) {
try {
return createBean(beanName, beanDefinition);
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
return null;
}
- 完整的ApplicationContext代码
public class ApplicationContext {
//配置类
public Class configClass;
//缓存单例的对象
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
//缓存包含Bean信息的BeanDefinition对象
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public ApplicationContext(Class configClass) { //传入带入@ComponentScan注解的配置类
this.configClass = configClass;
//解析
scan(configClass);
//缓存带有@Bean注解的方法 beanName为方法名
Method[] methods = configClass.getDeclaredMethods();
try {
Object o = configClass.newInstance();
for (Method method : methods) {
if (method.isAnnotationPresent(Bean.class)) {
method.setAccessible(true);
Object instance = method.invoke(o);
String beanName = method.getName();
//缓存调用方法返回的对象,beanName为方法名
singletonObjects.put(beanName, instance);
Class<?> clazz = method.getReturnType();
BeanDefinition beanDefinition = new BeanDefinition(clazz, "singleton");
beanDefinitionMap.put(beanName, beanDefinition);
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
//遍历beanDefinitionMap生成单例对象并缓存
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if ("singleton".equals(beanDefinition.getScope())) {
Object bean = null;
try {
bean = createBean(beanName, beanDefinition);
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
singletonObjects.put(beanName, bean);
}
}
}
//解析配置类
private void scan(Class configClass) {
//用来保存类的全限类名
List<String> list = new ArrayList<>();
//获取@Component注解里的包名
ClassLoader classLoader = ApplicationContext.class.getClassLoader();
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScanAnnotation = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
String path = componentScanAnnotation.value();
//包名 例如com.jxz.annotation 替换成 com/jxz/annotation
String realPath = path.replace(".", "/");
URL resource = classLoader.getResource(realPath);
File file = new File(resource.getFile());
//递归获取此文件里的所有以.class结尾的全限类名 保存到list里
getClassNames(file, list);
} else {
throw new RuntimeException("找不到指定配置信息");
}
list.stream().forEach(className -> {
try {
//获取每个类的Class对象
Class<?> clazz = classLoader.loadClass(className);
//判断是否有Component注解
if (clazz.isAnnotationPresent(Component.class)) {
Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
String beanName = componentAnnotation.value();
//先把clazz保存到BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
//如果有@Scope注解
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
String scope = scopeAnnotation.value();
if (!"singleton".equals(scope) && !"prototype".equals(scope)) {
throw new RuntimeException("不支持的Scope类型");
}
beanDefinition.setScope(scope);
} else {
beanDefinition.setScope("singleton");
}
//缓存
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
}
//反射创建对象
private Object createBean(String beanName, BeanDefinition beanDefinition) throws IllegalAccessException, InstantiationException {
//如果singletonObjects中已经存在则直接返回
Object o = singletonObjects.get(beanName);
if (null != o && "singleton".equals(beanDefinition.getScope())) {
return o;
}
Class clazz = beanDefinition.getClazz();
Object instance = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
Object bean = getBean(field.getName());
if (bean == null) {
BeanDefinition beanD = beanDefinitionMap.get(field.getName());
if (null != beanD) {
bean = createBean(field.getName(), beanD);
if ("singleton".equals(beanD.getScope())) {
singletonObjects.put(field.getName(), bean);
}
} else {
throw new RuntimeException("Can't autowired" + field.getName());
}
}
field.set(instance, bean);
}
}
return instance;
}
//递归获取file里所有类的全限类名
private void getClassNames(File file, List<String> classNames) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
if (f.isDirectory()) {
getClassNames(f, classNames);
}
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")) {
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\", ".");
classNames.add(className);
}
}
}
}
//获取bean方法
public Object getBean(String beanName) {
if (beanDefinitionMap.containsKey(beanName)) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//如果是单例的直接从缓存里取
if ("singleton".equals(beanDefinition.getScope())) {
Object o = singletonObjects.get(beanName);
return o;
}
//如果不是单例,使用createBean方法
if ("prototype".equals(beanDefinition.getScope())) {
try {
return createBean(beanName, beanDefinition);
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
return null;
}
}
- 测试
AppConfig
@ComponentScan("com.jxz.spring")
public class AppConfig {
@Bean
public User user(){
User user = new User();
user.setUserName("Hello");
user.setPassword("World");
return user;
}
}
User(测试@Bean注解)
public class User {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
Student(测试是否是多例)
@Component("student")
@Scope("prototype")
public class Student {
}
UserService(测试@Component和@Autowired)
@Component("userService")
public class UserService {
@Autowired
public User user;
}
- 测试类Test
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ApplicationContext(AppConfig.class);
User user = (User) applicationContext.getBean("user");
System.out.println(user);
Student student1 = (Student) applicationContext.getBean("student");
Student student2 = (Student) applicationContext.getBean("student");
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService);
System.out.println(userService.user);
}
}