1. 回顾注解
注解的存在主要是为了简化XML的配置。Spring6倡导全注解开发。
我们来回顾一下:
● 第一:注解怎么定义,注解中的属性怎么定义?
● 第二:注解怎么使用?
● 第三:通过反射机制怎么读取注解?
注解怎么定义,注解中的属性怎么定义?
package com.powernode.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Component {
String value();
}
以上是自定义了一个注解:Component
该注解上面修饰的注解包括:Target注解和Retention注解,这两个注解被称为元注解。
Target注解用来设置Component注解可以出现的位置,以上代表表示Component注解只能用在类和接口上。
Retention注解用来设置Component注解的保持性策略,以上代表Component注解可以被反射机制读取。
String value(); 是Component注解中的一个属性。该属性类型String,属性名是value。
1.1 自定义注解 69
package com.powernode.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//回顾注解 69
//自定义注解
// 标注注解的注解,叫做元注解。@Target注解用来修饰@Component可以出现的位置。
// 以下表示@Component注解可以出现在类上、属性上。
//@Target(value = {ElementType.TYPE, ElementType.FIELD})
// 以下表示@Component注解可以出现在类上
//@Target(value = {ElementType.TYPE})
// 使用某个注解的时候,如果注解的属性名是value的话,value可以省略。
//@Target({ElementType.TYPE})
// 使用某个注解的时候,如果注解的属性值是数组,并且数组中只有一个元素,大括号可以省略。
@Target(ElementType.TYPE)
// @Retention 也是一个元注解。用来标注@Component注解最终保留在class文件当中,并且可以被反射机制读取。
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
// 定义注解的属性
// String是属性类型
// value是属性名
String value();
// 其他的属性
// 属性类型String
// 属性名是name
//String name();
// 数组属性
// 属性类型是:String[]
// 属性名:names
//String[] names();
//int[] ages();
//int age();
}
2. 注解怎么使用? 70
package com.powernode.bean;
//使用自定义注解 70
import com.powernode.annotation.Component;
//@Component(属性名 = 属性值, 属性名 = 属性值, 属性名 = 属性值....)
//@Component(value = "userBean")
// 如果属性名是value,value可以省略。
@Component("userBean")
public class User {
}
用法简单,语法格式:@注解类型名(属性名=属性值, 属性名=属性值, 属性名=属性值......)
userBean为什么使用双引号括起来,因为value属性是String类型,字符串。
另外如果属性名是value,则在使用的时候可以省略属性名
2.1 通过反射机制怎么读取注解?70
package com.powernode.client;
import com.powernode.annotation.Component;
/**
* 通过反射机制读取注解 70
**/
public class ReflectAnnotationTest1 {
public static void main(String[] args) throws Exception{
// 通过反射机制怎么读取注解
// 获取类
Class<?> aClass = Class.forName("com.powernode.bean.User");
// 判断类上面有没有这个注解
if (aClass.isAnnotationPresent(Component.class)) {
// 获取类上的注解
Component annotation = aClass.getAnnotation(Component.class);
// 访问注解属性
System.out.println(annotation.value());
}
}
}
3. 注解之组件扫描原理 71
假设我们现在只知道包名:com.powernode.bean。至于这个包下有多少个Bean我们不知道。哪些Bean上有注解,哪些Bean上没有注解,这些我们都不知道,如何通过程序全自动化判断。
提示文件路径中不可有中文,所以这里我将代码放在
E:\java\spring6buchong的course17目录中
E:\java\spring6buchong\course17\src\main\java\com\powernode\client
ComponentScan
package com.powernode.client;
import com.powernode.annotation.Component;
import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* 注解之组件扫描原理 71
**/
public class ComponentScan {
public static void main(String[] args){
Map<String,Object> beanMap = new HashMap<>();
// 目前只知道一个包的名字,扫描这个包下所有的类,当这个类上有@Component注解的时候,实例化该对象,然后放到Map集合中。
String packageName = "com.powernode.bean";
// 开始写扫描程序。
// . 这个正则表达式代表任意字符。这里的"."必须是一个普通的"."字符。不能是正则表达式中的"."
// 在正则表达式当中怎么表示一个普通的"."字符呢?使用 \. 正则表达式代表一个普通的 . 字符。
String packagePath = packageName.replaceAll("\\.", "/");
//System.out.println(packagePath);
// com是在类的根路径下的一个目录。getSystemClassLoader系统类加载器
URL url = ClassLoader.getSystemClassLoader().getResource(packagePath);
String path = url.getPath();
//System.out.println(path);
// 获取一个绝对路径下的所有文件
File file = new File(path);
File[] files = file.listFiles();//获取bean目录下的所有子文件
Arrays.stream(files).forEach(f -> {
try {
//System.out.println(f.getName());
//System.out.println(f.getName().split("\\.")[0]);
String className = packageName + "." + f.getName().split("\\.")[0];
//System.out.println(className);
// 通过反射机制解析注解
Class<?> aClass = Class.forName(className);
// 判断类上是否有这个注解
if (aClass.isAnnotationPresent(Component.class)) {
// 获取注解
Component annotation = aClass.getAnnotation(Component.class);
String id = annotation.value();
// 有这个注解的都要创建对象
Object obj = aClass.newInstance();
beanMap.put(id, obj);
}
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println(beanMap);
}
}