基于Java反射 实现Spring的动态注入和依赖实现(新手,如果有不完善的希望指出)

适合人群 (掌握java反射.复习java反射,了解SpringBoot框架的自动注入)

该练习的小项目中存在的几处问题(已经知道的)

:::info

  • 扫描文件的时候Controller和Service层的顺序必须指定,在项目的结构中Service层必须在Controller层的上面(否则Cotroller层中的Service组件注入不了)

  • 在controller层的类中使用的Service属性必须是实现类,不能通过接口去引入,否则报错(静态上下文中,不能引入非静态方法 解决方法:给service接口中的方法添加上static关键字)

  • Controller类中必须有有参构造器(参数类型是Service层中的类或接口) 还必须有无参构造器

  • 类全名限定路径的选取的代码,不是很完善 :::

注解层

  • Autowired

  • Controller

  • Service

  • 注解的详细代码注释

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
​
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

:::danger 在上述代码中,我们 使用了@Target注解来指定该自定义注解只能用于类、接口或枚举类型上, 使用了@Retention注解来指定该注解在运行时可见,即可以通过反射机制获取该注解信息。 还使用了@interface关键字来定义一个注解类型,这个注解类型是一个类似接口的定义,但有一些特殊的限制。( @interface注解是一个特殊的Java注解,它用于定义自定义注解类型。) :::

@interface 注解的解释

:::danger @interface注解的作用是告诉编译器这个接口类型是一个注解类型。注解类型与普通的接口类型的不同在于,在定义注解类型时需要使用一些特殊的注解元素,例如@Target、@Retention、@Documented等,这些注解元素用于指定注解的作用目标、生存周期、注解是否包含在Java文档中等。

使用@interface注解可以定义一个标记型的接口类型,并在类、方法或其他程序元素上标记该接口类型,来表达某些额外的语义信息。例如,你可以定义一个名为@Service的注解类型,并在某个Java类上标记该注解来表示该类是一个服务类。

:::

@Service
public class MyService {
    // 该类的内容
}

:::danger 在上述代码中,通过在MyService类上标记@Service注解,表示该类是一个服务类。在Java中,为了让注解类型生效,需要使用Java中的注解处理器或反射机制来获取注解信息并进行相关的处理。 :::

Controller层

Serrvice层

接口

接口实现类

Model层

依赖注入工具类(主要就是使用反射和注解的联合使用实现属性的注入)

/**
 *扫描指定包下的所有的类 动态注入 与 依赖的注入
 * @param packageName
 */
public static void scanPackage(String packageName) {
//现获取该类所在包的路径
String path = DependencyInjection.class.getResource("/" + packageName.replace(".", "/")).getPath();
System.out.println("项目所在的地址"+path);
//将该类所在包下的所有类循环取出
for (File Package : new File(path).listFiles()) {
    String PackageName = path + "/" + Package.getName();
    System.out.println("包所在的地址"+ PackageName);
    for (File cls : new File(PackageName).listFiles()) {
        System.out.println("类的名字:"+cls.getName());
        String className = packageName + "."+ Package.getName() + "." + cls.getName().replace(".class", "");
        System.out.println("类全限定类型名" + className);
        try{
            Class<?> clazz = Class.forName(className);  //反射第一步
            //判断是否有注解标注 并且进行区分进行分别的处理
            if (clazz.isAnnotationPresent(Service.class)) {
                Object instance = clazz.newInstance();
                container.put(clazz.getName(), instance);
            }
            if (clazz.isAnnotationPresent(Controller.class)) {
                //直接创建出来先关的controller的实例
                Object instance = clazz.newInstance();
                //获取到该类中的全部属性
                Field[] fields = clazz.getDeclaredFields();
                //循环遍历判断是否存在Autowired注解 实现依赖的注入
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        // 如果被标注 Autowride的属性是Private私有的
                        //那么就会通过该方法将该属性的访问级别提高
                        field.setAccessible(true);
                        /**
                             * 在使用field.getType()方法获取到该成员变量所对应的Class对象后,
                             * 我们可以通过getName()方法获取到该Class对象的全限定类名,即类的包路径和类名的拼接字符串。
                             */
                        String fieldName = field.getType().getName();
                        if (container.get(fieldName) != null) {
                            Object dependency = container.get(fieldName);
                            //实现依赖的注入
                            /**
                                 * 我们需要将该实例对象设置到该对象实例中标记了该字段的位置,以实现依赖注入。
                                 * field.set()方法接受两个参数,分别是需要设置字段值的对象实例和字段值。
                                 * */
                            field.set(instance, dependency);
                        }
                    }
                }
                //将实例放入到容器中去
                container.put(clazz.getName(), instance);
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            ex.printStackTrace();
        }
​
    }
​
}
}
​
public static Object getBean(String name) {
return container.get(name);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值