概述
inverse of Control:控制反转
对象的创建和维护并不是由程序员完成的,而已由容器完成的
在一个项目由于代码的复杂性,要不断的new对象,这样可能会导致内存泄漏,如果有东西可以帮助程序员创建和销毁的话,那么就可以大大提高效率,比如IOC容器
一个简单的单例模式
public class ApplicationContext {
private static ConcurrentHashMap<Class, Object> singletonClassObjects = new ConcurrentHashMap<Class, Object>(256);
public static Object getBean(Class clazz){
if(singletonClassObjects.containsKey(clazz)){
return singletonClassObjects.get(clazz);
}else{
//创建对象
try {
Object obj = clazz.newInstance();
//将类放入到容器中
singletonClassObjects.put(clazz,obj);
return obj;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return null;
}
在代码中直接使用
UserService userService = (UserService) ApplicationContext.getBean(UserService.class);
DL
概述
dependence inject:依赖注入
在程序运行中,不同的类之间存在不同的传值的问题,在有了IOC容器之后,所有的对象都在IOC容器中,不同的类传值问题也可以由IOC容器负责
设计一个注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
String value() default "";
}
通过注解,自动从容器中获取对象
@Autowired
UserService userService;
实现思路
在程序运行之初,容器就需要知道所有放入容器类中被管理的类的相关信息
在获取信息之后容器要多类进行初始化,创建对象
在创建对象之后,要实现对象依赖关系(依赖注入)
再把创建完成的对象,放入到缓存中
代码实现
创建BeanDefinition
//用于存储类的信息定义
public class BeanDefinition {
Class<?> beanClass; //表示Bean类型,未加载类的时候存放Bean的名字,加载类后存放Bean的class信息。
// scope 表示Bean的作用域,一般值为单例或者原型。
// lazyInit:表示Bean是否是懒加载。
// initMethodName:Bean初始化需要执行的方法。
// destroyMethodName:Bean销毁时要执行的方法。
// factoryBeanName:创建当前Bean的工厂。
public Class<?> getBeanClass() {
return beanClass;
}
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
}
扫描需要被加载的类
//用于存储所有的放入到ioc容器bean的定义信息
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public ApplicationContext(){
//扫描包
scanAndParseToBeanDefinitions("com.java2022.shop");
for (String key :beanDefinitionMap.keySet()) {
System.out.println(key+":"+beanDefinitionMap.get(key).getBeanClass().getName());
}
}
//扫描包
private void scanAndParseToBeanDefinitions(String packagePath){
//将packagePath转换成路径
String url = packagePath.replace(".","/");
//根据packagePath获取路径
URL resource = ApplicationContext.class.getClassLoader().getResource(url);
//根据url创建文件对象
File file = new File(resource.getFile());
getBeanDefinition(file);
}
//得到bean的定义
private void getBeanDefinition(File file) {
if (file.isDirectory()) {
//遍历文件夹下所有的文件
for (File f : file.listFiles()) {
//获取文件的绝对路径
String absolutePath = f.getAbsolutePath();
if (absolutePath.endsWith(".class")) {
//获取类的全名称
String className = getFullyQualifiedClassName(absolutePath);
//System.out.println(className);
try {
//加载类
Class clazz = Class.forName(className);
//判断类是否有component注解
if (clazz.isAnnotationPresent(Component.class)) {
//解析类的注解获取Bean定义
parseClassToBeanDefinition(clazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else {
//进行递归操作
getBeanDefinition(f);
}
}
}
}
//将Bean的定义存储在容器中
private void parseClassToBeanDefinition(Class<?> clazz) {
String beanName = clazz.getDeclaredAnnotation(Component.class).value();
if (beanName == null || beanName.equals("")) {
beanName = clazz.getSimpleName();//将beanName设置成类的名称
}
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClass(clazz);
//将bean定义放入到容器中
beanDefinitionMap.put(beanName, beanDefinition);
}
//绝对路径转换成包名+类名
private String getFullyQualifiedClassName(String absolutPath) {
//剪切com.开头,到.class结尾文件
return absolutPath.substring(absolutPath.indexOf("com"), absolutPath.indexOf(".class")).replace(File.separator, ".");
}
根据definited创建对象,并且放入到ioc容器中
//根据BeanDefinition创建对象,并且将对象放入到ioc容器
private void createBeanToSingletonPool() {
//遍历beanDefinition,获取定义,创建对象
for (String key : beanDefinitionMap.keySet()) {
//创建bean
createBean(key, beanDefinitionMap.get(key));
}
System.out.println("bean创建完毕");
}
//创建bean的方法
private Object createBean(String beanName, BeanDefinition beanDefinition) {
//1,通过反射创建bean
//获取beanClass
Class beanClass = beanDefinition.getBeanClass();
try {
//判断容器中是否存在bean
Object beanObject;
if(singletonObjects.containsKey(beanName)){
beanObject= singletonObjects.get(beanName);
}else{
beanObject = beanClass.newInstance();//创建对象
//3,将创建完的bean对象放入到IOC容器中
singletonObjects.put(beanName,beanObject);
}
//2, 将bean的属性进行依赖注入
//获取所有的属性
Field[] fields = beanClass.getDeclaredFields();
for (Field field :fields) {
//判断属性是否由autowired注解
if(field.isAnnotationPresent(Autowired.class)){
//容器中获取属性对象,注入到当前的属性
field.setAccessible(true);
String fieldBeanName = field.getType().getSimpleName();
//注入属性
field.set(
beanObject,
getBean(fieldBeanName));//从容器中获取bean对象
}
}
return beanObject;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
throw new RuntimeException("创建对象失败,没有被容器接管");
}