仅仅是获取到注解信息还不够,还需要根据得到的信息做出一些反应,这样才能让人眼前一亮,心中明悟: 原来注解时这么用的 依赖注入容器的注解实现
一,定义两个表示电脑CPU与GraphicsCard的接口
package org.jy.sso.cas.data.server.system.annoAndReflect;
public interface CPU { // 描述CPU
void calculate(); // 接口方法
}
package org.jy.sso.cas.data.server.system.annoAndReflect;
public interface GraphicsCard { // 描述显卡的接口
void display();
}
二,编写上面接口的实现类
package org.jy.sso.cas.data.server.system.annoAndReflect;
public class IntelCPU implements CPU{
@Override
public void calculate() {
System.out.println("Intel CPU calculate.");
}
}
package org.jy.sso.cas.data.server.system.annoAndReflect;
public class NVIDIACard implements GraphicsCard{
@Override
public void display() {
System.out.println("Display something");
}
}
三,定义@Bean注解
package org.jy.sso.cas.data.server.system.annoAndReflect;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.FIELD}) // 该注解可以用在那些地方
@Retention(RetentionPolicy.RUNTIME) // 注解的什么周期
public @interface Bean {
Class<?> value(); // 元素的值是一个Class对象
}
四,编写注解处理器,实现依赖注入
package org.jy.sso.cas.data.server.system.annoAndReflect;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 注解工厂处理器
*/
public class AnnotationFactory {
/**
* 根据指定的Class对象,创建对应类的对象,
* 同时读取类中的@Bean注解,根据注解信息,实现依赖注入
* 该方法演示了注解信息获取与反射相关的方法
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
T obj = null;
try {
// 创建参数clazz代表的类的对象
obj = clazz.getConstructor().newInstance(); // 通过构造对象(Constructor)的静态方法newInstance()对象
// 得到类中所有声明的方法
Method[] methods = clazz.getDeclaredMethods();// 获得所有的方法描述类Method,
for (Method method : methods) {
Object implObject = getImplObject(method);// Method 实现了AnnotationElement接口,该方法取到筛选作用
if (implObject != null) {
// 调用方法,传入依赖的对象
method.invoke(obj, implObject);
}
}
// 得到类中声明的所有的字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
Object implObject = getImplObject(field); // 只获取到标准有@Bean注解的所有域
if (implObject != null) {
// 设置值
field.setAccessible(Boolean.TRUE);
field.set(obj, implObject); // 执行set方法及对应的值
field.setAccessible(Boolean.FALSE);
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
return obj;
}
/**
* 使用辅助方法,根据Bean注解的元素的值创建对应的对象,
* Field和Method类都实现了AnnotationElement接口
* 该实现类只处理标记有@Bean注解的方法
*
* @param element
* @return
* @throws NoSuchMethodException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private static Object getImplObject(AnnotatedElement element)
throws NoSuchMethodException,
InstantiationException,
IllegalAccessException,
InvocationTargetException { // 必须声明这些异常,否则clazz.getDeclaredConstructor().newInstance(); 必需要方法参数
if (element.isAnnotationPresent(Bean.class)) { // 判断element注解实现类是否有Bean这个注解
Bean beanAnnotation = element.getDeclaredAnnotation(Bean.class);
Class<?> clazz = beanAnnotation.value();
return clazz.getDeclaredConstructor().newInstance(); // 返回的是一个标注有@Bean注解的对象
}
return null;
}
}
五,使用注解@Bean标注类,
package org.jy.sso.cas.data.server.system.annoAndReflect;
/**
* 主要的牌子
*/
public class MainBoard {
@Bean(IntelCPU.class) // 依赖注入
private CPU cpu;
private GraphicsCard graphicsCard;
@Bean(NVIDIACard.class) // 依赖注入
public void setGraphicsCard(GraphicsCard graphicsCard) {
this.graphicsCard = graphicsCard;
}
// 验证对象是否自动创建,依赖注入
public void run() {
System.out.println("Starting computer...");
cpu.calculate();
graphicsCard.display();
}
}
六,执行下面的类,验证是否依赖注入
package org.jy.sso.cas.data.server.system.annoAndReflect;
/**
* 演示使用注解实现依赖注入
*/
public class ComputerRun {
public static void main(String[] args){
MainBoard mainBoard = AnnotationFactory.getBean(MainBoard.class);
mainBoard.run();
}
}
运行结果如下:
Starting computer...
Intel CPU calculate.
Display something