利用注解、反射和工厂模式设计一个简单的IoC容器,该IoC容器包含注解 @Component @Autowired @Configuration @ComponentScan和一个IoC容器类AnnotationConfigApplicationContext
时间: 2024-03-25 13:38:59 浏览: 106
好的,我来设计一个简单的IoC容器。
首先,我们需要定义注解:
```java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Configuration {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String[] value() default {};
}
```
这里定义了四个注解,分别是@Component、@Autowired、@Configuration和@ComponentScan。
@Component表示该类是一个组件,需要被IoC容器管理。
@Autowired表示该属性需要被自动注入。
@Configuration表示该类是一个配置类,用于配置IoC容器。
@ComponentScan表示需要扫描的包路径。
接下来,我们定义一个IoC容器类:
```java
public class AnnotationConfigApplicationContext {
private Map<String, Object> beans = new HashMap<>(); // 存储所有的bean
private Map<Class<?>, Object> configurationBeans = new HashMap<>(); // 存储所有的@Configuration类
private Set<Class<?>> componentClasses = new HashSet<>(); // 存储所有的@Component类
public AnnotationConfigApplicationContext(Class<?> configurationClass) {
scan(configurationClass);
registerBeans();
autowireBeans();
}
private void scan(Class<?> configurationClass) {
ComponentScan componentScan = configurationClass.getAnnotation(ComponentScan.class);
if (componentScan != null) {
String[] basePackages = componentScan.value();
for (String basePackage : basePackages) {
Set<Class<?>> classes = ClassScanner.getClasses(basePackage);
for (Class<?> clazz : classes) {
if (clazz.isAnnotationPresent(Component.class)) {
componentClasses.add(clazz);
}
}
}
}
}
private void registerBeans() {
for (Class<?> clazz : componentClasses) {
Object bean = createBean(clazz);
beans.put(clazz.getName(), bean);
}
for (Class<?> clazz : configurationBeans.keySet()) {
Object bean = configurationBeans.get(clazz);
beans.put(clazz.getName(), bean);
}
}
private Object createBean(Class<?> clazz) {
try {
Object instance = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
String beanName = field.getType().getName();
Object bean = beans.get(beanName);
if (bean == null) {
throw new RuntimeException("Can not find bean: " + beanName);
}
field.setAccessible(true);
field.set(instance, bean);
}
}
return instance;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Create bean failed: " + clazz.getName());
}
}
private void autowireBeans() {
for (Object bean : beans.values()) {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
String beanName = field.getType().getName();
Object autowiredBean = beans.get(beanName);
if (autowiredBean == null) {
throw new RuntimeException("Can not find bean: " + beanName);
}
field.setAccessible(true);
try {
field.set(bean, autowiredBean);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
public <T> T getBean(Class<T> clazz) {
Object bean = beans.get(clazz.getName());
if (bean == null) {
throw new RuntimeException("Can not find bean: " + clazz.getName());
}
return (T) bean;
}
public <T> T getBean(String beanName) {
Object bean = beans.get(beanName);
if (bean == null) {
throw new RuntimeException("Can not find bean: " + beanName);
}
return (T) bean;
}
}
```
这个IoC容器类包含了三个方法:scan()、registerBeans()和autowireBeans()。
scan()方法用于扫描所有的@Component类,并将它们保存到componentClasses中。
registerBeans()方法用于创建所有的bean,并将它们保存到beans中。
autowireBeans()方法用于自动注入所有的bean。
最后,我们定义一个测试类:
```java
@Configuration
@ComponentScan({"com.example.demo"})
public class AppConfig {
}
@Component
public class UserDao {
public void save() {
System.out.println("Save user");
}
}
@Component
public class UserService {
@Autowired
private UserDao userDao;
public void save() {
userDao.save();
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.save();
}
}
```
这个测试类中,我们定义了一个@Configuration类AppConfig,用于配置IoC容器,并指定需要扫描的包路径。
另外,我们定义了一个UserDao类和一个UserService类,它们都被标注为@Component,表示需要被IoC容器管理。
在UserService类中,我们使用@Autowired注解自动注入UserDao对象。
最后,在main()方法中,我们创建了一个AnnotationConfigApplicationContext对象,并传入AppConfig.class作为构造函数参数。然后,我们从容器中获取UserService对象,并调用它的save()方法。
阅读全文