一, 项目整体结构
创建maven项目创建如图所示的结构
二,annotation包
2.1 Bean.java
package com.best.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
2.2,DI.java
package com.best.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DI {
}
三,bean包
3.1,AnnotationApplicationContext.java
package com.best.bean;
import com.best.annotation.Bean;
import com.best.annotation.DI;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class AnnotationApplicationContext implements ApplicationContext{
// 创建map集合,放bean对象
private final Map<Class<?>,Object> beanFactory = new HashMap<>();
public static String rootPath;
//返回对象
@Override
public Object getBean(Class<?> clazz) {
return beanFactory.get(clazz);
}
//设置包的扫描规则
//当前包以及子包 那个类有@Bean注解,就把这个类通过反射实例化
// basePackage 包的路径
public AnnotationApplicationContext(String basePackage) throws Exception {
//com.xxxx
//1. 把 . 替换成 \
String packagePath = basePackage.replaceAll("\\.", "\\\\");
//2. 获取包的绝对路径
Enumeration<URL> urls = Thread.currentThread()
.getContextClassLoader()
.getResources(packagePath);
while (urls.hasMoreElements()){
URL url = urls.nextElement();
String filePath = URLDecoder.decode(url.getFile(), "utf-8");
//获取包前面路径部分进行截取,字符串截取
rootPath = filePath.substring(0, filePath.length() - packagePath.length());
//包扫描
loadBean(new File(rootPath));
//属性注入
loadDI();
}
}
//属性注入
private void loadDI() {
//实例化对象在beanFactory的map集合里面
//1. 遍历beanFactory的map集合
Set<Map.Entry<Class<?>, Object>> entries = beanFactory.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
//2. 获取map集合每个对象(value),每个对象属性获取到
Object obj = entry.getValue();
//获取对象的Class
Class<?> clazz = obj.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
//3. 遍历得到每个对象属性数组,得到每个属性
for (Field field : declaredFields) {
//4. 判断属性上是否有@DI注解
DI annotation = field.getAnnotation(DI.class);
if(annotation != null) {
//如果是私有属性,涉设置可以使用
field.setAccessible(true);
//5. 如果有@DI注解,把对象进行设置(注入)
try {
//设置值
field.set(obj,beanFactory.get(field.getType()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
//包扫描过程, 实例化
private void loadBean(File file) throws Exception {
//1. 判断当前是否是文件夹
if(file.isDirectory()){
//2. 获取文件夹里所有的内容
File[] childrenFiles = file.listFiles();
//3. 判断文件夹里为空直接返回
if(childrenFiles == null || childrenFiles.length == 0){
return;
}
//4. 文件夹里面不为空,遍历文件夹里的所有内容
for (File child : childrenFiles) {
//4.1 遍历每一个File对象,继续判断,如果还是文件,递归
if(child.isDirectory()){
loadBean(child);
}
else{
//4.2 遍历得到File对象不是文件夹,是文件
//4.3 得到包路径+类名称部分-字符串截取
String pathWithClass =
child.getAbsolutePath().substring(rootPath.length() - 1);
//4.4 判断当前文件夹类型是否为.class
if(pathWithClass.contains("class")) {
//4.5 如果是.class类型,把路径\替换成. 把.class去掉
// com.best.service.UserServiceImpl
String allName = pathWithClass.replaceAll("\\\\", ".")
.replaceAll(".class", "");
//4.6 判断类上是否有注解@Bean,如果有就实例化过程
//4.6.1 获取类的Class
Class<?> clazz = Class.forName(allName);
//4.6.2 判断不是接口
if(!clazz.isInterface()){
//4.6.3 判断类上受否有注解@Bean
Bean annotation = clazz.getAnnotation(Bean.class);
if(annotation != null) {
//4.6.4 实例化对象
Object instance = clazz.getConstructor().newInstance();
//4.7 把对象实例化之后,放到map集合beanFactory中
//4.7.1 判断当前类如果有接口,让接口class作为map的key
if(clazz.getInterfaces().length>0) {
beanFactory.put(clazz.getInterfaces()[0],instance);
} else {
beanFactory.put(clazz,instance);
}
}
}
}
}
}
}
}
}
3.2,Application.java 接口
package com.best.bean;
public interface ApplicationContext {
Object getBean(Class<?> clazz);
}
四,测试类和测试方法
4.1,dao包和service包
4.1.1,UserDao接口和UserDaoImpl实现类
UserDao.java
package com.best.dao;
public interface UserDao {
void add();
}
UserDaoImpl.java
package com.best.dao.impl;
import com.best.annotation.Bean;
import com.best.dao.UserDao;
@Bean
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao add......");
}
}
UserService.java接口
package com.best.service;
public interface UserService {
void add();
}
UserServiceImpl.java实现类
package com.best.service.impl;
import com.best.annotation.Bean;
import com.best.annotation.DI;
import com.best.dao.UserDao;
import com.best.service.UserService;
@Bean
public class UserServiceImpl implements UserService {
@DI
private UserDao userDao;
@Override
public void add() {
userDao.add();
}
}
4.2,测试类TestUser.java
package com.best;
import com.best.bean.AnnotationApplicationContext;
import com.best.bean.ApplicationContext;
import com.best.service.UserService;
public class TestUser {
public static void main(String[] args) throws Exception {
ApplicationContext context =
new AnnotationApplicationContext("com.best");
UserService userService = (UserService) context.getBean(UserService.class);
System.out.println(userService);
userService.add();
}
}
测试结果如图:
补充pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.best</groupId>
<artifactId>spring6</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>spring-first</module>
<module>spring6-ioc-xml</module>
<module>spring6-ioc-annotation</module>
<module>spring6-reflect</module>
<module>spring-ioc</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>