文章目录
容器的增删改查
- 容器的增删改查
- 测试用例
- 容器的增加删除操作, 往容器中添加和删除bean
- 根据Class获取对应实例: 根据Map的key获取值
- 获取所有的Class和实例
- 通过注解获取被注解标注的Class
- 通过超类获取对应子类的Class (通过传入接口获取接口对应实现类的Class对象, 例如传入Service的接口, 获取Service的实现类.)
- 获取容器载体存储的Class的数量
上面的需求实现的代码如下
/**
* 添加一个class 对象和bean实例到容器中
*
* @param clazz Class 对象
* @param bean bean实例
* @return 返回添加的值
*/
public Object addBean(Class clazz, Object bean) {
return beanMap.put(clazz, bean);
}
/**
* 移除一个IOC容器管理对象
*
* @param clazz
* @return 被移除的对象, 如果不存在则返回null
*/
public Object removeBean(Class clazz) {
return beanMap.remove(clazz);
}
/**
* 根据Class对象 获取bean 的实例
*
* @param clazz
* @return
*/
public Object getBean(Class clazz) {
return beanMap.get(clazz);
}
/**
* 获取容器管理的所有的Class对象集合 (获取所有的key)
*
* @return Class 集合
*/
public Set getClasses() {
return beanMap.keySet();
}
/**
* 获取所有Bean 集合 (获取所有的value)
*
* @return
*/
public Set getBeans() {
// 获取所有的bean集合, 并通过构造函数, 传入HashSet中
return new HashSet(beanMap.values());
}
/**
* 通过指定的注解, 查找被该注解标记的Class集合 .
*
* @param annotation
* @return
*/
public Set getClassesByAnnotation(Class annotation) {
// 1.获取beanMap的所有Class对象
Set keySet = getClasses();
if (ValidationUtil.isEmpty(keySet)) {
log.warn("容器为空!");
return null;
}
// 2.通过注解筛选被注解标记的class对象, 并添加到ClassSet中
Set classSet = new HashSet();
for (Class clazz : keySet) {
// 判断该类是否被指定的注解标记
if (clazz.isAnnotationPresent(annotation)) {
classSet.add(clazz);
}
}
// 判断符合条件的集合是否存在,如果不存在, 则返回Null
return classSet.size() > 0 ? classSet : null;
}
/**
* 通过接口或父类获取实现类或子类的Class 集合, 不包含其本身
*
* @param interfaceOrClass
* @return
*/
public Set getClassesBySuper(Class interfaceOrClass) {
// 1.获取beanMap的所有Class对象
Set keySet = getClasses();
if (ValidationUtil.isEmpty(keySet)) {
log.warn("容器为空!");
return null;
}
// 2.判断KeySet里的元素是否为传入的接口或类的子类, 如果是, 就添加到ClassSet中
Set classSet = new HashSet();
for (Class clazz : keySet) {
// 判断KeySet里的元素是否为传入的接口或类的子类
/**
* isAssignableFrom 方法
* A.isAssignableFrom(B)
* A 是否为B的爸爸或爷爷或祖孙...
* 返回true, 代表是的, 返回false. 代表B不是继承或实现了A
* 特殊情况: A.isAssignableFrom(A) 返回的也是 true.
* 因此此处加上了!clazz.equals(interfaceOrClass) 来排除自身接口或类的情况
*/
if (interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)) {
classSet.add(clazz);
}
}
// 判断符合条件的集合是否存在,如果不存在, 则返回Null
return classSet.size() > 0 ? classSet : null;
}
其中 通过接口或父类获取实现类或子类的Class 集合这个方法, 有用到Class类的isAssignableFrom方法, 该方法用于判断是否是某个类的超类, 特殊情况: A.isAssignableFrom(A) 返回的也是 true.
测试用例完整的测试用例如下 . 其中有用到TestMethodOrder
注解, 标注在测试类上, 用于规定测试用例执行的顺序的. 在每个测试用例的方法中标注上@Order()
, 数字越小的越先执行. 由于该测试类中的方法要先加载容器, 因此需要把加载容器的方法Order顺序传入最小.
import com.springstudy.HelloServlet;
import com.springstudy.controller.frontend.MainPageController;
import com.springstudy.service.solo.HeadLineService;
import com.springstudy.service.solo.impl.HeadLineServiceImpl;
import org.junit.jupiter.api.*;
import org.simpleframework.core.annotation.Controller;
// 单元测试的方法, 按顺序执行
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BeanContainerTest {
private static BeanContainer beanContainer;
/**
* BeforeAll注解用于所有的测试用例执行之前 , 执行仅且一次初始化.
*/
@BeforeAll
static void init() {
// 初始化 BeanContainer 实例
beanContainer = BeanContainer.getInstance();
}
@DisplayName("加载目标类及实例到BeanContainer")
// 第一个执行
@Order(1)
@Test
public void loadBeansTest() {
Assertions.assertEquals(false, beanContainer.isLoaded());
beanContainer.loadBeans("com.springstudy");
int size = beanContainer.size();
Assertions.assertEquals(7, size);
Assertions.assertEquals(true, beanContainer.isLoaded());
}
@DisplayName("根据类获取其实例")
@Order(2)
@Test
public void getBeanTest() {
MainPageController controller = (MainPageController) beanContainer.getBean(MainPageController.class);
Assertions.assertEquals(true, controller instanceof MainPageController);
HelloServlet helloServlet = (HelloServlet) beanContainer.getBean(HelloServlet.class);
Assertions.assertEquals(null, helloServlet);
}
@DisplayName("根据注解获取对应的类的集合")
@Order(3)
@Test
public void getClassesByAnnotationTest() {
// 获取被自定义Controller注解标记的类对象
int size = beanContainer.getClassesByAnnotation(Controller.class).size();
Assertions.assertEquals(3, size);
}
@DisplayName("根据接口获取实现类")
@Order(4)
@Test
public void getClassesBySuperTest() {
// 通过传入HeadLineService接口, 获取其所有实现类, 断言判断是否有 HeadLineServiceImpl
boolean isContains = beanContainer.getClassesBySuper(HeadLineService.class)
.contains(HeadLineServiceImpl.class);
Assertions.assertEquals(true, isContains);
}
}
运行测试类, 结果如下