ioc原理
首先明白一个概念ioc是一个容器,用来存储实例化对象的
那么可以明白一点,如何将对象放到ioc容器中,其次就是如何将对象从ioc中拿出来
类似于如下
存入ioc容器
首先我们肯定不能手动将对象put进去,我们可以像spring那样去扫描注解‘’
那么如何去扫描注解呢?
自定义注解
这个大家去自学一下
这里简单说一下
@Retention
是 Java 中的一个元注解,用于指定被它注解的注解应该保留多久。它有一个 RetentionPolicy
参数,定义了注解的生命周期,包括三个值:
-
RetentionPolicy.SOURCE
: 注解仅保留在源代码中,编译时会被忽略,不会包含在编译后的字节码中。这类注解通常用于提供给编译器做进一步的处理。 -
RetentionPolicy.CLASS
: 注解会被包含在编译后的字节码中,但在运行时无法获取。这是默认的保留策略,如果不显式指定的话。 -
RetentionPolicy.RUNTIME
: 注解会被包含在编译后的字节码中,并且可以在运行时通过反射获取。这种保留策略通常用于在运行时处理注解信息。
@Target
是 Java 中的元注解之一,用于指定注解可以应用的地方。它定义了一个 ElementType
参数,表示注解可以应用的目标元素类型。
-
ElementType.TYPE
: 表示注解可以应用在类、接口(包括注解类型)或枚举声明。 -
ElementType.FIELD
: 表示注解可以应用在字段(包括枚举常量)声明。 -
ElementType.METHOD
: 表示注解可以应用在方法声明。
自定义注解写法
元注解(元注解的作用是负责注解其他注解。 Java5.0 定义了 4 个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作说明。)
public @interface 注解名称{
}
定义一个自定义的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyComponent {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAutowired {
}
那么好了我们定义出了注解
定义ioc容器(其实就是一个map)
rivate Map<String, Object> beans = new HashMap<>();
ok,那么开始书写autowired与component的关系
第一步: 先找到所有的带有component的类
第二步: 将其实例化并加入到map中
第三步: 基于第一步的map便利找到所有的带有autowired注解的类
第四步: 实现自动注入
下面是我写的代码偷了个懒
好了现在实现第一步
public class ClassScanner {
public List<Class<?>> getClasses(String packageName) throws IOException {
try{
String path=packageName.replace(".","/");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();//获取当前线程的类加载器
Enumeration<URL> resources = classLoader.getResources(path);//获取类路径下的class
List<File> dirs = new ArrayList<>();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
List<Class<?>> classes = new ArrayList<>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
List<Class<?>> classes = new ArrayList<>();//初始化一个泛型List用于装载class
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
if (files == null) {
return classes;
}
try{
for (File file:files){
if (file.isDirectory()){
assert !file.getName().contains(".");
classes.addAll(findClasses(file, packageName + "." + file.getName()));
}else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
}
}
}catch (Exception e){
e.printStackTrace();
}
return classes;
}
第二步: 将其实例化并加入到map中
注意一下createInstance方法取出的是第一个构造函数
public class SimpleIoCContainer {
private Map<String, Object> beans = new HashMap<>();
public void scanAndInitialize(String packageName){
ClassScanner classScanner=new ClassScanner();
try{
for (Class<?> clazz:classScanner.getClasses(packageName)){
if (clazz.isAnnotationPresent(WyComponent.class)) {
// 实例化类
Object instance = createInstance(clazz);
// 将实例添加到容器中
beans.put(clazz.getSimpleName(), instance);
// 进行依赖注入
injectDependencies(instance);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
private Object createInstance(Class<?> clazz) throws InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<?> constructor = clazz.getDeclaredConstructors()[0];
Object[] args = new Object[constructor.getParameterCount()];;
return constructor.newInstance(args);
}
第三步
第四步
其实为了省事写到了前面
具体实现代码
public void injectDependencies(Object instance) throws IllegalAccessException {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(WyAutowired.class)) {
Object dependency = beans.get(field.getType().getSimpleName());
field.setAccessible(true);//设置可访问,无论是共有还是私有
field.set(instance, dependency);//设置属性
}
}
}