在 Spring 中, 我们可以通过 @Autowired 注解的方式为一个方法中注入参数, 那么这种方法背后到底发生了什么呢, 这篇文章将讲述如何用 Java 的注解和反射实现一个 "低配版" 的依赖注入.
下面是我们要做的一些事情:
通过 @interface 的方式定义一个注解
为某个希望杯被注入的方法添加这个注解
编写测试代码, 通过反射获取添加了注解的方法对应的 Method 对象, 将该方法对象设置为可访问的, 通过反射创建对象并调用这个方法, 同时注入依赖数据
如上所述, 我们分为三个步骤, 去加工出这个低配版的依赖注入, 下面就来讲讲每一步的详细步骤
我们要编写的代码的结构分为三部分:
Autowired: 声明的注解
Demo 类: 含有被依赖注入的方法 setStr
Test 类: 通过反射获取被 Autowired 注解的方法, 并进行依赖注入
一: 定义注解
- Autowired
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Autowired {
- }
首先我们通过 @interface 的方式定义的一个注解, 由此也可以看出注解的地位和类, 接口类似, 是一种同一级的关系
@Retention 是元注解, 故名思义, 它是用来注解 (动词) 注解 (名词) 的注解!(名词),RetentionPolicy.RUNTIME 表示会将这个注解保留到运行时, 这样的话我们就能通过反射去处理注解了.
二. 为被注入的方法添加注解
下面我们为 setStr 方法添加一个注解
- public class Demo {
- private String str;
- @Autowired
- public void setStr (String str) {
- this.str = str;
- }
- public String getStr () {
- return str;
- }
- }
三. 通过反射的方式获取并处理被注解的方法, 将该方法对象设置为可访问的, 通过反射创建对象并调用这个方法, 同时注入依赖数据
由于涉及到大量关于反射的 API, 所以对于反射机制话可以看看我以前写的这篇文章: https://www.cnblogs.com/penghuwan/p/7580145.html
在这一步骤我们要做的事情:
调用 Class.forName 方法, 传入某个类的路径字符串为参数, 获取该类的 Class 对象
通过调用该类 Class 对象的 getDeclaredMethods 方法, 获得声明方法对应的 Methods 对象组成的数组
遍历 2 中的 Methods 数组, 通过调用 Method 对象的 isAnnotationPresent 方法判断该方法有没有加上 Autowired 注解, 并对其中加上 Autowired 注解的方法做以下处理
通过调用 Method 对象的 setAccessible(true); 方法将对象设置为可访问的, 不这么搞下一步调用方法会出错
通过 Class 对象的 newInstance 方法创建对象实例, 假设其为 object, 则再通过 method.invoke(object, "传入的数据")调用对象的方法, 注入依赖数据
将 5 中的对象实例 object 返回, 我们就获得了被注入了依赖数据的对象实例了
代码如下:
- Test.java
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- public class Test {
- /**
- * 这个方法会将一段文本注入到某个类中添加了 @Autowired 注解的方法中, 并将实例对象返回
- */
- public static Object injectStrToInstance (String ClassName,String str) throws ClassNotFoundException {
- // 获取 Demo 的 Class 对象
- Class demoClass = Class.forName(ClassName);
- // 从 Class 对象中获取 Demo 中声明方法对应的 Method 对象
- Method [] methods = demoClass.getDeclaredMethods();
- for (Method method : methods) {
- // 判断方法是否被加上了 @Autowired 这个注解
- if(method.isAnnotationPresent(Autowired.class)) {
- // 将方法设置为可调用的
- method.setAccessible(true);
- try {
- Object object = demoClass.newInstance();
- // 调用 method 方法, 向其中注入 str 字符串
- method.invoke(object,str);
- return object;
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- }
- }
- }
- return null;
- }
- public static void main (String args []) throws ClassNotFoundException {
- // 进行依赖注入, 并取得注入后的 Demo 的对象实例
- Demo demo1 = (Demo)injectStrToInstance("Demo", "我是被注入的文本");
- // 输出一下看看我们的文本是不是被成功注入进去了
- System.out.println(demo1.getStr());
- }
- }
输出结果:
我是被注入的文本
到此为止, 我们就完成了这个低配版的依赖注入了
来源: https://www.cnblogs.com/penghuwan/p/9360602.html