target
掌握注解方式将bean纳入到ioc容器
掌握@ComponentScan 注解的使用
了解使用@ComponentScan 注解定义扫描规则
掌握使用 @import注解将bean纳入到IOC容器
掌握使用 @Value注解给属性赋值
掌握使用 @Scope给bean设置作用域
掌握 生命周期相关的注解
Spring IOC容器往简单了说就是存放各种类型的bean的容器。在程序中最直观的体现方式就是xml配置文件,在配置文件中,我们可以通过bean标签存入各种类型的bean。下面我们通过xml配置文件的方式来操作一组bean:
Student类:
package com.lee.spring.bean;
public class Student {
private int no;
private String name;
//getter、setter略
}
- 将bean加入到IOC容器:
在src 下新建配置文件 applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.lee.spring.bean.Student">
<property name="no" value="1001"></property>
<property name="name" value="zs"></property>
</bean>
</beans>
- 从IOC容器取bean操作:
@Test
public void test01() {
//1.获取到IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从容器中获取bean
Student student = (Student) context.getBean("student");
}
其实上面的操作同样用注解来完成
1. @Configuration + @Bean
一个普通的类加一个注解@Configuration就变成了配置类,配置类就相当于xml配置文件。
package com.lee.spring.config;
@Configuration
public class MyConfig {
}
相当于:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
1.1 将bean纳入到IOC容器
定义一个方法,在方法上加注解@Bean。这个方法就变成了bean组件。
方法的返回值类型 = bean标签的的class
方法的名字 = bean标签的id
package com.lee.spring.config;
@Configuration
public class MyConfig {
/**
* 方法的返回值类型:相当于bean标签的class
* 方法的名字:相当于bean标签的id
*/
@Bean
public Student student() {
Student student = new Student(2002,"ls");
return student;
}
}
默认情况方法名就是bean的id值,可以修改:@Bean("stu")
1.2 从IOC容器取bean
用注解方式获取IOC容器需要用到ApplicationContext的一个实现类AnnotationConfigApplicationContext
在AnnotationConfigApplicationContext类中,可以按住 command + O (或者outline视图)看一下构造方法:
一般情况选择传入 class类型参数的构造方法。
编写测试方法进行测试:
@Test
public void test02() {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
Student student = (Student) context.getBean("student");
System.out.println(student);
}
2. @ComponentScan
有一个Person类,如何其纳入到IOC容器?
package com.lee.spring.bean;
public class Person {
}
2.1 @Component注解方式
第一步:将 Person 类标上组件注解 @Component
package com.lee.spring.bean;
import org.springframework.stereotype.Component;
@Component
public class Person {
}
在配置文件applicationContext.xml
中开启包扫描:
<context:component-scan base-package="com.lee.spring"></context:component-scan>
base-package 包含 com.lee.spring 和 com.lee.spring的所有子包。
编写测试方法进行测试:
@Test
public void test03() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//getBeanDefinitionNames()方法可以获取所有IOC容器中的bean
String[] names = context.getBeanDefinitionNames();
for (String name : names){
System.out.println(name);
}
}
输出:
person
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
...
注意:
- IOC容器中会包含一些spring自带的bean
2.2 @ComponentScan注解方式
@ComponentScan 注解也能实现将组件扫描到IOC容器中。
实现方法:
直接在配置类上加@ComponentScan注解,然后括号里写上需要扫描的包即可。
package com.lee.spring.config;
@Configuration
@ComponentScan("com.lee.spring")
public class MyConfig {
...
}
编写测试方法,看一下容器中都有什么组件:
@Test
public void testAnnotation() {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
String[] names = context.getBeanDefinitionNames();
for (String name : names){
System.out.println(name);
}
}
输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
person
...
2.3 设置扫描规则
点开@ComponetScan注解里面,我们会发现有这样两个方法:
这两个方法是包含过滤器
和排除过滤器
,我们可以用这两个方法设置扫描规则。这里的扫描规则就是规定扫描哪些包,不扫描哪些包。
① excludeFilters
excludeFilters 是排除过滤器。
ComponentScan.Filter[] excludeFilters() default {};
观察这行代码:
方法名excludeFilters表示可以排除很多过滤器。
返回值类型是ComponentScan.Filter类型的数组。
default{}表示默认什么都没有排除,可以自定义排除。
既然排除的是一个数组,所以用{}包裹起来:
@ComponentScan(value = "com.lee.spring",excludeFilters = { })
{}里面可以放好多ComponentScan.Filter,这里我们暂时写进来一个:
@ComponentScan(value = "com.lee.spring",excludeFilters = {@ComponentScan.Filter})
继续点击@ComponentScan.Filter,看一下里面都有什么:
发现Filter注解里面有一个FilterType类型的type,有一个Class数组类型的value,所以我们将这两个值写上。
@ComponentScan(value = "com.lee",excludeFilters = {@ComponentScan.Filter(type = ,value = )})
下面步骤配置type:
继续点进FilterType,看一下:
发现是FilterType是一个枚举,默认是:FilterType.ANNOTATION
@ComponentScan(value = "com.lee",excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = )})
下面步骤配置value:
value是一个Class数组类型,把需要排除的Class写进去就行。
@ComponentScan(value = "com.lee",excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value =Person.class )})
这表示排除的是Person类,如果想再排除User类,直接在后面加就可以。
@ComponentScan(value = "com.lee",excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value ={Person.class, User.class})})
② includeFilters
@ComponentScan(value = "com.lee",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value ={Service.class, Controller.class})},useDefaultFilters = false)
注意:
- includeFilters是包含的意思,就是包含配置的Controller层和Service层,但是必须关闭默认过滤器行为才有效:useDefaultFilters = false
FilterType
FilterType是一个枚举,包含以下:
其中:
ANNOTATION:表示过滤某一类注解,比如Controller注解、Service注解,所以带有这种注解的类全部会被过滤。
-
ASSIGNABLE_TYPE:表示过滤某个具体的类。比如:StudentController类。
@ComponentScan(value = "com.lee",includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value ={StudentController.class})},useDefaultFilters = false)
-
CUSTOM:表示自定义过滤哪些类。
- 配置类:MyConfig.java
@ComponentScan(value = "com.lee",includeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM,value ={MyFilter.class})},useDefaultFilters = false)
- 自定义过滤器类:MyFilter.java,需要实现TypeFilter接口
public class MyFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { ClassMetadata classMetadata = metadataReader.getClassMetadata(); String className = classMetadata.getClassName();//获取所有三层注解的类名 if (className.contains("User")){ return true; } return false; } }
所有包含User的三层类,全部会被过滤。例如:UserController,UserService等。
3. @import
回顾一下:把bean纳入到IOC容器的几种方式:
方式一:配置文件中配置
<bean id="stu" class="com.lee.entity.Student" ></pre>
方式二:配置类中用@Bean注解
@Configuration
public class MyConfig {
@Bean("stu")
public Student student() {
Student student = new Student(2002,"ls");
return student;
}
}
除了上述两种方式外,@import注解也能把bean纳入到IOC容器中:
🌰将 Apple类和 Banana类纳入到IOC容器:
苹果类:
package com.lee.spring.bean;
public class Apple {
}
香蕉类:
package com.lee.spring.bean;
public class Banana {
}
配置类:
package com.lee.spring.config;
@Configuration
@Import({Apple.class, Banana.class})
public class MyConfig {
}
测试:
@Test
public void test05() {
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
com.lee.entity.Apple
com.lee.entity.Banana
发现,苹果类和香蕉了已经成功纳入到IOC容器。
注意,@import注解纳入到IOC容器的bean的id是全类名。
4. @Value
通过@Value可以将外部的值动态注入到Bean中,可以为基本类型数据和String类型数据的变量注入数据
🌰为Computer类注入值:
package com.lee.spring.bean;
@Component("computer")
public class Computer {
@Value("Apple")
private String brand;
@Value("100")
private double price;
}
在配置文件 applicationContext.xml
中配置包扫描:
<context:component-scan base-package="com.lee.spring"></context:component-scan>
编写测试方法进行测试:
@Test
public void test06() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Computer computer = (Computer)context.getBean("computer");
System.out.println(computer);
}
控制台输出:
Computer [brand=Apple, price=100.0]
说明值已经成功注入。
上述方式是直接为属性赋值,还可以读取配置文件进行赋值:
在 src下新建 jdbcConfig.properties:
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/test
jdbc.username = root
jdbc.password = root
用 $
获取配置文件的值,并且赋值给属性:
package com.lee.spring.bean;
@Component("conn")
@PropertySource("classpath:jdbcConfig.properties")
public class Connection {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}
5. @Scope
作用:
用于指定bean的作用范围。
属性:
singleton:
prototype:
request:
session:
🌰
package com.lee.spring.config;
@Configuration
public class MyConfig {
@Bean("pc")
@Scope("singleton")
public Computer computer() {
Computer pc = new Computer();
return pc;
}
}
6. 生命周期相关的注解
@PostConstruct
注解标注的方法是初始化方法。
@PreDestroy
注解标注的方法是销毁方法。
🌰演示User的生命周期:
package com.lee.spring.bean;
@Component("user")
public class User {
public User() {
System.out.println("User的无参构造");
}
@PostConstruct
public void myInit() {
System.out.println("User的初始化方法执行");
}
@PreDestroy
public void myDestroy() {
System.out.println("User的销毁方法执行");
}
}
在配置文件 applicationContext.xml 中配置扫描:
<context:component-scan base-package="com.lee.spring.bean"></context:component-scan>
测试方法:
@Test
public void test08() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User)context.getBean("user");
((ClassPathXmlApplicationContext)context).close();
}
控制台打印:
User的无参构造
User的初始化方法执行
User的销毁方法执行