1、 首先定义一个类上的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DadaBean {}
2、定义一个类中属性的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DadaBean {}
3、 编写一个实例化bean的接口
public interface ApplicationContext {
Object getBean(Class clazz);
}
4、实现这个实例化接口的类【核心代码
】
- 初始化Bean对象的开发注意点
-
- 1.1. 判断当前是否文件夹
- 1.2. 获取文件夹里面的所有内容
- 1.3. 判断文件夹里面为空直接返回
- 1.4. 如果文件夹不为空,遍历文件夹所有内容
- 1.4.1. 遍历得到每个File对象,继续判断,如果还是文件夹,递归
- 1.4.2. 遍历得到File对象不是文件夹,是文件
- 1.4.3. 得到包的路径+类名称部分-字符串截取
- 1.4.4. 判断当前文件夹是否为.class结尾
- 1.4.5. 如果是.class类型,把路径\替换成. 并且把。class去掉【
cn.itzd
.service.UserServiceImpl】 - 1.4.6. 判断类上面是否有注解@DadaBean,如果有就实例化过程
- 1.4.7. 把对象实例化之后放到map集合中
-
- 属性的注入开发注意点
-
- 遍历map集合中的实例化对象
- 获取集合中每个对象的value,得到每个属性
- 遍历得到每个对象属性数组,得到每个属性
- 判断属性上是否有@DadaDi注解(如果是私有属性,需要开启设置值,也就是setAccessible(true))
- 如果有@DadaDi注解,把对象进行设置
-
package cn.itzd.bean;
import cn.itzd.anno.DadaBean;
import cn.itzd.anno.DadaDi;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author: dada
* @Date: 2023/4/5 22:33
* @Version: 1.0
* @Description: 基于注解扫描bean
*/
public class AnnotationApplicationContext implements ApplicationContext {
//存储bean的容器
private final Map<Class<?>, Object> beanFactory = new ConcurrentHashMap<>();
//本地磁盘路径
private static String rootPath;
@Override
public Object getBean(Class clazz) {
return beanFactory.get(clazz);
}
/**
* 根据包扫描加载bean
* @param basePackage 传过来的包路径
*/
public AnnotationApplicationContext(String basePackage) {
try {
String packageDirName = basePackage.replaceAll("\\.", "\\\\");
Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8);
rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
loadBean(new File(filePath));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 递归遍历所有的.class类
* @param file
* 1. 判断当前是否文件夹
* 2. 获取文件夹里面的所有内容
* 3. 判断文件夹里面为空直接返回
* 4. 如果文件夹不为空,遍历文件夹所有内容
* 4.1. 遍历得到每个File对象,继续判断,如果还是文件夹,递归
* 4.2. 遍历得到File对象不是文件夹,是文件
* 4.3. 得到包的路径+类名称部分-字符串截取
* 4.4. 判断当前文件夹是否为.class结尾
* 4.5. 如果是.class类型,把路径\替换成. 并且把。class去掉【cn.itzd.service.UserServiceImpl】
* 4.6. 判断类上面是否有注解@DadaBean,如果有就实例化过程
* 4.7. 把对象实例化之后放到map集合中
*/
private void loadBean(File file) {
try {
//判断当前是否文件夹
if (!file.isDirectory()) {
return;
}
//判断文件夹里面为空直接返回
File[] childrenFiles = file.listFiles();
if (childrenFiles == null || childrenFiles.length == 0) {
return;
}
//遍历得到每个File对象,继续判断,如果还是文件夹,递归
for (File childrenFile : childrenFiles) {
if (childrenFile.isDirectory()) {
loadBean(childrenFile);
} else {
//得到包的路径+类名称部分-字符串截取
String pathWithClass = childrenFile.getAbsolutePath().substring(rootPath.length() - 1);
//判断当前文件夹是否为.class结尾
if (!pathWithClass.endsWith(".class")) {
continue;
}
String allName = pathWithClass.replaceAll("\\\\", "\\.").replace(".class", "");
//判断类上面是否有注解@DadaBean,如果有就实例化过程,结构不需要实例化
Class<?> clazz = Class.forName(allName);
if (clazz.isInterface()) {
continue;
}
//判断类上面是否有注解@DadaBean,如果有就实例化过程
DadaBean annotation = clazz.getAnnotation(DadaBean.class);
if (annotation == null) {
continue;
}
Object instance = clazz.getConstructor().newInstance();
//判断当前类有接口,就让接口的class作为map的key
if (clazz.getInterfaces().length > 0) {
beanFactory.put(clazz.getInterfaces()[0],instance);
}else {
beanFactory.put(clazz,instance);
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
//支持属性的注入
loadDi();
}
/**
* 支持属性的注入
* 1. 遍历map集合中的实例化对象
* 2. 获取集合中每个对象的value,得到每个属性
* 3. 遍历得到每个对象属性数组,得到每个属性
* 4. 判断属性上是否有@DadaDi注解(如果是私有属性,需要开启设置值,也就是setAccessible(true))
* 5. 如果有@DadaDi注解,把对象进行设置
*/
private void loadDi() {
//遍历
beanFactory.forEach((k,v) -> {
//获取value对象
Class<?> clazz = v.getClass();
//获取每个类中的属性值
Field[] declaredFields = clazz.getDeclaredFields();
//判断属性上是否有@DadaDi注解
for (Field declaredField : declaredFields) {
DadaDi dadaDi = declaredField.getAnnotation(DadaDi.class);
if (dadaDi == null) {
continue;
}
//如果是私有属性,需要开启设置值
declaredField.setAccessible(true);
//如果有@DadaDi注解,把对象进行设置
try {
System.out.println("正在给【"+clazz.getName()+"】属性【" + declaredField.getName() + "】注入值【"+ beanFactory.get(declaredField.getType()).getClass().getName() +"】");
declaredField.set(v,beanFactory.get(declaredField.getType()));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
});
}
}
5、业务代码中开始调用
- 用户接口类
public interface UserService {
void out();
}
- 用户接口实现
@DadaBean
public class UserServiceImpl implements UserService {
@DadaDi
private UserDao userDao;
@Override
public void out() {
System.out.println("Service层执行结束");
userDao.print();
}
}
- dao持久层接口
public interface UserDao {
void print();
}
- dao层接口的实现
@DadaBean
public class UserDaoImpl implements UserDao{
@Override
public void print() {
System.out.println("Dao层执行结束");
}
}
- 测试通过
public class UserTest { public static void main(String[] args) { ApplicationContext context = new AnnotationApplicationContext("cn.itzd"); UserService userService = (UserService)context.getBean(UserService.class); System.out.println(userService); userService.out(); } }