Spring之手写一个依赖注入容器
- 1. 创建两个自定义注解
-
- 2. ApplicationContext接口与实现类
-
- 2.1 ApplicationContext 接口
- 2.2 实现类:DefaultListableApplicationContext
- 3. 定义DAO层和Service层及其实现
- 4. 定义异常信息类
-
- 4.1 InjectBeanException
- 4.2 NotExistsBean
- 4.3 NotSupportMoreSuperInterface
- 5. 测试自定义bean容器(带依赖注入)
-
- 5.1 新建测试类TestUser
- 5.2 输出结果
1. 创建两个自定义注解
1.1 Component注解
@Target(value = ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
1.2 DI注解
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DI {
String value() default "";
}
2. ApplicationContext接口与实现类
2.1 ApplicationContext 接口
public interface ApplicationContext {
Object getBean(String name);
<T> T getBean(String name, Class<T> clazz);
boolean exists(String name);
boolean exists(String name, Class<?> clazz);
}
2.2 实现类:DefaultListableApplicationContext
public class DefaultListableApplicationContext implements ApplicationContext {
private Map<String, Object> objectsMap = new ConcurrentHashMap<>(128);
private Map<Class, Object> objectsTypeMap = new ConcurrentHashMap<>(128);
private Logger log = LoggerFactory.getLogger(DefaultListableApplicationContext.class);
private String basePath;
public DefaultListableApplicationContext(String basePackage) {
String packagePath = basePackage.replaceAll("\\.", "\\\\");
try {
URL url = Thread.currentThread().getContextClassLoader().getResource(packagePath);
if (StringUtils.hasText(url.getPath())) {
String filePath = URLDecoder.decode(url.getFile(), "UTF8");
basePath = filePath.substring(0, filePath.length() - packagePath.length());
loadBeans(new File(filePath));
loadDI();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
@Nullable
public Object getBean(String name) {
return objectsMap.get(name);
}
@Override
@Nullable
public <T> T getBean(String name, Class<T> clazz) {
Object obj = objectsMap.get(name);
if (obj == null) {
Object bean;
if ((bean = objectsTypeMap.get(clazz)) == null) {
for (Class<?> interfaceClazz : clazz.getInterfaces()) {
if ((bean = objectsTypeMap.get(interfaceClazz)) != null)
return (T) bean;
getBean(name, interfaceClazz);
}
return null;
}
return (T) bean;
}
return clazz.isInstance(obj) ? clazz.cast(obj) : null;
}
@Override
public boolean exists(String name) {
return objectsMap.get(name) == null ? false : true;
}
@Override
public boolean exists(String name, Class<?> clazz) {
if (objectsMap.get(name) == null) {
if (objectsTypeMap.get(clazz) == null) {
for (Class<?> interfaceClazz : clazz.getInterfaces()) {
if (objectsTypeMap.get(interfaceClazz) != null)
return true;
exists(name, interfaceClazz);
}
return false;
}
return true;
}
return true;
}
private void loadBeans(File file) {
if (file.isDirectory()) {
File[] childrenFiles = file.listFiles();
if (childrenFiles == null || childrenFiles.length == 0) {
return;
}
for (File childFile : childrenFiles) {
if (childFile.isDirectory()) {
loadBeans(childFile);
} else {
String pathWithClass = childFile.getAbsolutePath().substring(basePath.length() - 1);
if (pathWithClass.endsWith(".class")) {
String allName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
try {
Class<?> clazz = Class.forName(allName);
if (!clazz.isInterface()) {
if (clazz.getAnnotation(Component.class) != null) {
Object instance = clazz.getConstructor().newInstance();
if (StringUtils.hasText(clazz.getAnnotation(Component.class).value())) {
String beanName = clazz.getAnnotation(Component.class).value();
objectsMap.put(beanName, instance);
log.warn(">>> objectsMap store bean(name,obj) ===> (" + beanName + "," + instance + ")");
if (clazz.getInterfaces().length == 1) {
objectsTypeMap.put(clazz.getInterfaces()[0], instance);
log.warn(">>> objectsTypeMap store bean(class,obj) ===> (" + clazz.getInterfaces()[0].getSimpleName() + "," + instance + ")");
} else if (clazz.getInterfaces().length == 0) {
objectsTypeMap.put(clazz, instance);
log.warn(">>> objectsTypeMap store bean(class,obj) ===> (" + clazz.getInterfaces()[0].getSimpleName() + "," + instance + ")");
} else {
throw new NotSupportMoreSuperInterface("Not support the bean that has more than two super interfaces.");
}
}
else if (clazz.getInterfaces().length > 0) {
String interfaceName = clazz.getInterfaces()[0].getSimpleName();
String beanName = lowercaseFirstLetter(interfaceName);
objectsMap.put(beanName, instance);
log.warn(">>> objectsMap store bean(name,obj) ===> (" + beanName + "," + instance + ")");
objectsTypeMap.put(clazz.getInterfaces()[0], instance);
log.warn(">>> objectsTypeMap store bean(class,obj) ===> (" + clazz.getInterfaces()[0].getSimpleName() + "," + instance + ")");
}
else {
String beanName = lowercaseFirstLetter(clazz.getSimpleName());
objectsMap.put(beanName, instance);
log.warn(">>> objectsMap store bean(name,obj) ===> (" + beanName + "," + instance + ")");
objectsTypeMap.put(clazz, instance);
log.warn(">>> objectsTypeMap store bean(class,obj) ===> (" + clazz.getInterfaces()[0].getSimpleName() + "," + instance + ")");
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
}
private void loadDI() {
for (Map.Entry<String, Object> entry : objectsMap.entrySet()) {
Object obj = entry.getValue();
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
if (field.getAnnotation(DI.class) != null) {
Class<?>[] interfaces = field.getType().getInterfaces();
String needWiredBeanName;
Object autoWiredBean;
if (StringUtils.hasText(needWiredBeanName = field.getAnnotation(DI.class).value())) {
autoWiredBean = objectsMap.get(needWiredBeanName);
if (autoWiredBean != null) {
field.set(obj, autoWiredBean);
log.warn("<<< DI: Class " + clazz.getSimpleName() + " of field named " + field.getName() + " is injected with value of " + autoWiredBean + " from " + "objectsMap, by value of annotation @DI");
continue;
}
}
needWiredBeanName = lowercaseFirstLetter(field.getType().getSimpleName());
if ((autoWiredBean = objectsMap.get(needWiredBeanName)) != null || (autoWiredBean = objectsTypeMap.get(field.getType())) != null) {
field.set(obj, autoWiredBean);
log.warn("<<< DI: Class " + clazz.getSimpleName() + " of field named " + field.getName() + " is injected with value of " + autoWiredBean + " , by value or type of property itself ");
continue;
}
if (interfaces.length > 0) {
for (Class<?> interfaceClazz : interfaces) {
String interfaceClazzName = interfaceClazz.getSimpleName();
if (interfaceClazz.isAssignableFrom(field.getType())) {
needWiredBeanName = lowercaseFirstLetter(interfaceClazzName);
if ((autoWiredBean = objectsMap.get(needWiredBeanName)) != null || (autoWiredBean = objectsTypeMap.get(interfaceClazz)) != null) {
field.set(obj, autoWiredBean);
log.warn("<<< DI: Class " + clazz.getSimpleName() + " of field named " + field.getName() + " is injected with value of " + autoWiredBean + ", by value or type of super interface");
}
}
}
continue;
}
throw new InjectBeanException("There occurs an Exception while injecting property filed [" + field.getName() + "] of Class <" + clazz.getSimpleName() + "> , because bean factory doesn't exist the bean named " + needWiredBeanName);
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
private String lowercaseFirstLetter(String name) {
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
}
3. 定义DAO层和Service层及其实现
public interface UserDao {
void addUser(User user);
}
@Component("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void addUser(User user) {
System.out.println();
System.out.println("------------------>>>执行UserDaoImpl中的addUser方法开始<<<<------------------");
System.out.println("\t\t\t\t\t\t名字\t\t\t\t年龄");
System.out.println("\t\t\t\t\t\t"+user.getName()+"\t\t\t\t"+user.getAge());
System.out.println("------------------>>>执行UserDaoImpl中的addUser方法完毕<<<<------------------");
}
}
public interface UserService {
void add();
}
@Component("userService")
public class UserServiceImpl implements UserService {
@DI("userDao")
private UserDaoImpl userDao;
@Override
public void add() {
System.out.println("》》》 user service impl execute add method...");
User user = new User("张三", 25);
userDao.addUser(user);
}
}
4. 定义异常信息类
4.1 InjectBeanException
public class InjectBeanException extends RuntimeException{
public InjectBeanException() {
super();
}
public InjectBeanException(String message) {
super(message);
}
}
4.2 NotExistsBean
public class NotExistsBean extends RuntimeException{
public NotExistsBean() {
}
public NotExistsBean(String message) {
super(message);
}
}
4.3 NotSupportMoreSuperInterface
public class NotSupportMoreSuperInterface extends RuntimeException{
public NotSupportMoreSuperInterface() {
super();
}
public NotSupportMoreSuperInterface(String message) {
super(message);
}
}
5. 测试自定义bean容器(带依赖注入)
5.1 新建测试类TestUser
public class TestUser {
public static void main(String[] args) {
DefaultListableApplicationContext context = new DefaultListableApplicationContext("com.ypy.context");
UserService userService = context.getBean("aaa", UserServiceImpl.class);
UserDao userDao = context.getBean("userDaoImpl", UserDao.class);
boolean existFlag = context.exists("aaa");
System.out.println("UserService exists ? " + existFlag);
System.out.println("从Bean容器中获取aaa对象地址: " + userService);
System.out.println("从Bean容器中获取userDao对象地址: " + userDao);
userService.add();
}
}
5.2 输出结果
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsMap store bean(name,obj) ===> (userDao,com.ypy.context.dao.impl.UserDaoImpl@2b193f2d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsTypeMap store bean(class,obj) ===> (UserDao,com.ypy.context.dao.impl.UserDaoImpl@2b193f2d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsMap store bean(name,obj) ===> (userService,com.ypy.context.service.impl.UserServiceImpl@7a81197d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsTypeMap store bean(class,obj) ===> (UserService,com.ypy.context.service.impl.UserServiceImpl@7a81197d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: <<< DI: Class UserServiceImpl of field named userDao is injected with value of com.ypy.context.dao.impl.UserDaoImpl@2b193f2d from objectsMap, by value of annotation @DI
UserService exists ? false
从Bean容器中获取aaa对象地址: com.ypy.context.service.impl.UserServiceImpl@7a81197d
从Bean容器中获取userDao对象地址: com.ypy.context.dao.impl.UserDaoImpl@2b193f2d
》》》 user service impl execute add method...
------------------>>>执行UserDaoImpl中的addUser方法开始<<<<------------------
名字 年龄
张三 25
------------------>>>执行UserDaoImpl中的addUser方法完毕<<<<------------------
Process finished with exit code 0