一、了解IOC
- 依赖一个类似工厂的IOC容器
- 将对象的创建、依赖关系的管理以及生命周期交由IOC容器管理
- 降低系统在实现上的复杂性和耦合度,易于扩展,满足开闭原则
依赖注入DI,上层控制下层
依赖注入的方式
- Setter
- Interface
- Constructor
- Annotation
IOC容器优势
- 避免在各处使用new来创建类,并且可以做到统一维护
- 创建实例的时候不需要了解其中的细节
- 反射+工厂模式的合体,满足开闭原则
二、IOC容器的实现
需要实现的点:
-
提取标记对象
-
指定范围,获取范围内的所有类
- 使用类加载器
-
-
- 遍历所有类,获取被注解标记的类并加载进容器里
-
实现容器
-
容器的组成部分
- 保存Class对象及其实例的载体
-
容器的加载 的实现思路
- 配置的管理与获取–使用ConcurrentHashMap进行实例存储
- 获取指定范围内的Class对象
- 依据配置提取Class对象,连同实例一并存入容器
-
代码实例
Bean容器实现代码
/**
* @NoArgsConstructor(创建一个没有参数的构造器)
* @author :LY
* @date :Created in 2021/4/5 11:23
* @modified By:
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer {
/**
* ConcurrentHashMap并发性好,jdk1.8后进行了大改进,摒弃了分段锁概念,利用了cas和红黑树来细化锁的粒度和提升扩容效率,进一步提升并发性能
* 存放所有被配置标记的目标对象的Map
*/
private final Map<Class<?>,Object> beanMap = new ConcurrentHashMap();
/**
* 加载bean的注解列表
*/
private static final List<Class<? extends Annotation>> BEAN_ANNOTATION
= Arrays.asList(Component.class, Controller.class, Service.class, Repository.class);
/**
* 获取Bean容器实例
* @return
*/
public static BeanContainer getInstance(){
return ContainerHolder.HOLDER.instance;
}
private enum ContainerHolder{
HOLDER;
private BeanContainer instance;
//默认是private访问权限
ContainerHolder(){
instance = new BeanContainer();
}
}
/**
* 容器是否已经被加载过
*/
private boolean loaded = false;
/**
* 是否加载该Bean
* @return 是否已加载
*/
public boolean isLoaded(){
return loaded;
}
/**
* Bean实例数量
* @return 数量
*/
public int size(){
return beanMap.size();
}
/**
* 扫描加载所有Bean
* @param packageName 包名
*/
public synchronized void loadBeans(String packageName){
//判断bean容器是否被加载过
if (isLoaded()){
log.warn("BeanContainer has been loaded.");
return;
}
Set<Class<?>> classSet = ClassUtil.extractPackageClass(packageName);
if (ValidationUtil.isEmpty(classSet)){
log.warn("extract nothing from packageName " + packageName);
return;
}
//lambda表达式,等价于foreach
classSet.forEach(clazz->{
BEAN_ANNOTATION.forEach(annotation ->{
//如果类上标记了定义的注解
if (clazz.isAnnotationPresent(annotation)){
//将目标本身作为键,目标类的实例作为值,放入到beanMap中
beanMap.put(clazz,ClassUtil.newInstance(clazz,true));
}
});
});
loaded = true;
}
}
测试提取类
@DisplayName("加载目标类及其实例到BeanContainer : loadBeansTest")
@Test
public void loadBeansTest(){
Assertions.assertEquals(false,beanContainer.isLoaded());
beanContainer.loadBeans("com.w2cs");
Assertions.assertEquals(6,beanContainer.size());
Assertions.assertEquals(true,beanContainer.isLoaded());
}
测试通过
-
容器的操作方式
- 增加、删除操作
- 根据Class获取对应实例
- 获取所有的Class和实例
- 通过注解来获取被注解标注的Class
- 通过超类获取对应的子类Class
- 获取容器载体保存Class的数量
容器操作代码
/**
* 添加一个class对象及其Bean实例
* @param clazz Class对象
* @param bean Bean实例
* @return 原有的Bean实例,没有则返回null
*/
public Object addBean(Class<?> clazz,Object bean){
return beanMap.put(clazz,bean);
}
/**
* 移除一个IOC容器管理的对象
* @param clazz Class对象
* @return 删除的Bean实例,没有则返回null
*/
public Object removeBean(Class<?> clazz){
return beanMap.remove(clazz);
}
/**
* 根据Class对象湖区Bean实例
* @param clazz Class对象
* @return Bean实例
*/
public Object getBean(Class<?> clazz){
return beanMap.get(clazz);
}
/**
* 获取容器管理的所有Class对象集合
* @return Class集合
*/
public Set<Class<?>> getClasses(){
return beanMap.keySet();
}
/**
* 获取所有Bean集合
* @return Bean集合
*/
public Set<Object> getBean(){
return new HashSet<>(beanMap.values()) ;
}
/**
* 根据注解筛选出Bean的Class集合
* @param annotation 注解
* @return Class集合
*/
public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation){
//1.获取beanMap的所有class集合
Set<Class<?>> keySet = getClasses();
if (ValidationUtil.isEmpty(keySet)){
log.warn("noting in beanMap");
return null;
}
//2.通过注解筛选被注解标记的class对象,并添加到classSet里
Set<Class<?>> classSet = new HashSet<>();
keySet.forEach(clazz->{
//类是否有相关的注解标记
if (clazz.isAnnotationPresent(annotation)){
classSet.add(clazz);
}
});
return classSet.size()>0?classSet:null;
}
/**
* 通过接口或者父类获取实现类或者子类的Class集合,不包括其本身
* @param interfaceOrClass 接口或者父类Class
* @return Class集合
*/
public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass){
//1.获取beanMap的所有class集合
Set<Class<?>> keySet = getClasses();
if (ValidationUtil.isEmpty(keySet)){
log.warn("noting in beanMap");
return null;
}
//2.判断keySet里的元素是否是传入的接口或者类的子类,如果是,并添加到classSet里
Set<Class<?>> classSet = new HashSet<>();
keySet.forEach(clazz->{
//判断keySet里的元素是否是传入的接口或者类的子类
if (interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)){
classSet.add(clazz);
}
});
return classSet.size() > 0 ? classSet : null;
}
- 实现容器的依赖注入(目前容器里面管理的Bean实例仍可能是不完备的)
-
实例里面某些必须的成员变量还没有创建
-
实现思路
- 定义相关的注解标签
- 实现创建被注解标记的成员变量实例,并将其注入到成员变量里
- 依赖注入的使用(暂时只支持成员变量的注入)
-
代码
/**
* @author :LY
* @date :Created in 2021/4/6 16:47
* @modified By:
*/
@Slf4j
public class DependencyInjector {
/**
* Bean容器
*/
private BeanContainer beanContainer;
public DependencyInjector(){
//获取容器实例
beanContainer = BeanContainer.getInstance();
}
/**
* 执行依赖注入 通过类型注入
*/
public void doIoc(){
//1.遍历Bean容器中所有的Class对象
if (ValidationUtil.isEmpty(beanContainer.getClasses())){
log.warn("empty classes in BeanContainer");
return;
}
for (Class<?> clazz : beanContainer.getClasses()){
//2.遍历Class对象的所有成员变量
Field[] fields = clazz.getDeclaredFields();
if (ValidationUtil.isEmpty(fields)){
continue;
}
for (Field field : fields) {
//3.找出被Autowired标记的成员变量
if (field.isAnnotationPresent(Autowired.class)){
Autowired autowired = field.getAnnotation(Autowired.class);
String autowiredValue = autowired.value();
//4.获取这些成员变量的类型
Class<?> fieldClass = field.getType();
//5.获取这些成员变量的类型在容器里对应的实例
Object fieldValue = getFieldInstance(fieldClass,autowiredValue);
if (fieldValue == null){
throw new RuntimeException("unable to inject relevant type , target fieldClass is:" + fieldClass.getName());
}else {
//6.通过反射将对应的成员变量实例注入到成员变量所在类的实例里
Object targetBean = beanContainer.getBean(clazz);
ClassUtil.setField(field,targetBean,fieldValue,true);
}
}
}
}
}
/**
* 从容器中获取实例对象
* @param fieldClass 实例类型
* @param autowiredValue 指定具体实现 在接口拥有多个实现时需要指定
* @return
*/
private Object getFieldInstance(Class<?> fieldClass,String autowiredValue) {
Object fieldValue = beanContainer.getBean(fieldClass);
if (fieldValue != null){
return fieldValue;
}else {
//如果是接口的话,获取它的实现类类型
Class<?> implementedClass = getImplementClass(fieldClass,autowiredValue);
if (implementedClass != null){
return beanContainer.getBean(implementedClass);
}else {
return null;
}
}
}
/**
* 获取接口
* @param fieldClass
* @return
*/
private Class<?> getImplementClass(Class<?> fieldClass,String autowiredValue) {
Set<Class<?>> classSet = beanContainer.getClassesBySuper(fieldClass);
if (!ValidationUtil.isEmpty(classSet)){
//出现多个实现类
if (ValidationUtil.isEmpty(autowiredValue)){
//用户没告诉具体实现类,有以下几种情况
if (classSet.size() == 1){
//容器里只有一个实现类,直接返回
return classSet.iterator().next();
}else {
//容器里有多个,用户并未指定实现类,则抛出异常
throw new RuntimeException("multipe implemented classes for "+ fieldClass.getName()+" please set @Autowired's value to pick one");
}
}else {
for (Class<?> clazz : classSet) {
if (autowiredValue.equals(clazz.getSimpleName())){
//获取到用户指定的实例
return clazz;
}
}
}
}
return null;
}
}