1. Spring IoC注解式开发
为了进一步,运用注解,这里我们看看下面这个需求。
目前只知道一个包
com.rianbowsea
的名字,扫描这个包下所有的类,当这个类上有@Compoent 注解的时候,实例化该对象,然后放到Map集合中。
package com.rainbowsea;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 使用某个注解的时候,如果注解的属性值是数组,并且数组中只有一个元素,大括号可以省略。
@Target(ElementType.TYPE)
// @Retention 也是一个元注解,用来标注@Component 注解最终保留在class 文件当中,并且可以被反射机制读取
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
// 定义注解的属性
// String 是属性类型
// value 是属性名
String value();
}
package com.rainbowsea;
//
//@Component(value = "userBean",属性名 = 属性值,属性名 = 属性值,属性名 = 属性值...)
//@Component(value = "userBean")
// 如果属性名是 value,value 可以省略
@Component("userBean")
public class User {
}
package com.rainbowsea;
@Component("orderBean")
public class Order {
}
package com.rainbowsea;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class ComponentScan {
/*
目前只知道一个包的名字,扫描这个包下所有的类,当这个类上有@Compoent 注解的时候,
实例化该对象,然后放到Map集合中
*/
public static void main(String[] args) {
//定义一个集合存储其中的实例化对象
Map<String,Object> beanMap = new HashMap<>();
String packageName = "com.rainbowsea";
// 开始扫描程序
// .这个正则表达式表示任意字母,这里的“.” 必须是一个普通的"."字符,不能是正则表达式中的“.”
// 在正则表达式当中怎么表示一个普通的"." 字符呢?使用"\",在Java当中一个“/” 要用两个“//” 表示
String packagePath = packageName.replaceAll("\\.", "/");
//System.out.println(packagePath);
// com 是在类的根路径下的一个目录
// url 是一个绝对路径
URL url = ClassLoader.getSystemClassLoader().getResource(packagePath);
String path = url.getPath();
//System.out.println(path);
// 获取一个绝对路径下的所有文件
File file = new File(path);
File[] files = file.listFiles();
Arrays.stream(files).forEach(file1 -> {
//System.out.println(file1);
//System.out.println(file1.getName().split("\\.")[0]);
// 拼接成:全限定类名
String className = packageName + "." + file1.getName().split("\\.")[0];
// 再通过反射机制,解析注解
Class<?> aClass = null;
try {
aClass = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
// 判断该类是否含有该 Component.class 注解
if(aClass.isAnnotationPresent(Component.class)) {
// 获取注解
Component annotation = aClass.getAnnotation(Component.class);
// 获取到该注解的值
String id = annotation.value();
// 有这个注解的都要创建对象
try {
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
Object obj = declaredConstructor.newInstance();
// 将创建好的实例化对象存储到 Map 当前去。
beanMap.put(id,obj);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
});
System.out.println(beanMap);
}
}
运行结果:
3. Spring 声明Bean的注解
注解的存在主要是为了简化XML的配置。Spring6倡导全注解开发。
在Spring 当中,负责声明 Bean 的注解的,常见的有如下四个:
- @Compoent
- @Controller
- @Service
- @Repository
通过源码可以看到,@Controller、@Service、@Repository 这三个注解都是@Component注解的别名。换句话说:这四个注解的功能都一样。用哪个都可以。
只是为了增强程序的可读性,建议:
-
控制器类上使用:Controller
-
service类上使用:Service
-
dao类上使用:Repository
他们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字
3.1 Spring注解的使用
如何使用以上的注解呢?
- 第一步:加入aop的依赖
- 第二步:在配置文件中添加context命名空间
- 第三步:在配置文件中指定扫描的包
- 第四步:在Bean类上使用注解
第一步:加入aop的依赖
还是第一步,通过Maven 导入相关的 jar 包,在 pom.xml
文件当中。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rainbowsea.reflect</groupId>
<artifactId>spring6-oo8-anotation-blog</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.11</version>
</dependency>
<!-- junit4 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
</project>
我们可以看到当加入spring-context依赖之后,会关联加入aop的依赖。所以这一步不用做。
第二步:在配置文件中添加context命名空间
注意:这里所说的配置文件是指,我们配置 bean 对象的那个配置.xml
的配置文件信息。如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
第三步:在配置文件中指定扫描的包
注意:这里所说的配置文件是指,我们配置 bean 对象的那个配置.xml
的配置文件信息。如下:
指定扫描的包: 是指明Spring 在那个包路径下,可以找到要实例化的 Bean 对象。
<!-- 指定扫描的包,-->
<context:component-scan base-package="com.rainbowsea.reflect.sprint.bean"></context:component-scan>