配置类组件
注解 | 说明 |
@Configuratioin | 把一个类作为IoC容器,它的某个方法上如果添加了@Bean,那么就会作为这个Spring容器中的Bean。 |
@ComponentScan | 在配置类上添加此注解,该注解默认扫描该类所在包下的所有配置类,相当于之前的<context:component-scan> |
@Scope | 用于指定scope作用域(用在类上) |
@Lazy | 表示延迟初始化 |
@Conditional | Spring4开始提供,作用是按照一定的条件进行判断,如果满足条件则给容器注册Bean |
@Import | 导入外部资源 |
生命周期控制 | @PostConstruct用于指定初始化方法(用在方法上) @PreDestroy用于指定销毁方法(用在方法上) @DependsOn定义Bean初始化和销毁的顺序 |
@Configuratioin
原始xml方式写法
application.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="user" class="com.lucifer.project.entity.User">
<property name="username" value="Lucifer"/>
<property name="address" value="xian"/>
<property name="age" value="18"/>
</bean>
</beans>
调用方式
public class MyTest {
@Test
public void test() {
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
// 如果定义了bean的id,优先以自定义value为准
// 如果没定义,默认获取类名首字母小写
Object user = ac.getBean("user");
System.out.println(user); // User{username='Lucifer', address='xian', age=18}
}
}
使用@Configuration注解
@Configuration
public class MyConfig {
// 默认获取类名首字母小写,其次是方法名
// 如果定义了@Bean的value,优先以自定义value为准
@Bean("user")
public User user() {
return new User("Lucifer", "xian", 18);
}
}
public class MyTest {
@Test
public void test2() {
ApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
// Bean name默认是是方法名
// 如果定义了@Bean的value,优先以自定义value为准
Object user = ac.getBean("user");
System.out.println(user); // User{username='Lucifer', address='xian', age=18}
}
}
@ComponentScan
原始xml方式写法
<context:component-scan base-package="com.lucifer.project.entity"/>
通过注解写法
@Configuration
@ComponentScan(value = "com.lucifer.project",
//includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)},
includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyController.class)},
includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, value = MyTypeFilter.class)},
useDefaultFilters = false)
public class ComponentScanConfig {
}
public class MyTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类所有的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前扫描到的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取到当前类的所有资源
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
if (className.contains("Controller")) {
return true;
}
return false;
}
}
public class MyTest {
@Test
public void test3() {
ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentScanConfig.class);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
System.out.println(Arrays.toString(beanDefinitionNames).replaceAll(",", "\n"));
}
}
@Scope
Scope有四种范围:
singleton:单例,默认scope prototype:原型,多例,每次都会是新的一个对象 request:主要用于web模块,同一次请求值创建一个实例 session:主要用于web模块, 同一个session只创建一个实例
@Configuration
public class MyConfig {
@Scope("singleton")
public User user() {
return new User("Lucifer", "xian", 18);
}
}
@Lazy:使当前类延时加载
默认不延时加载,如果加上此注解则使当前类延时加载
延时加载只针对单例Bean(即@Scope为singleton的Bean)起作用
加上此注解后容器启动时不创建对象,调用对象的功能时才创建对象
@Configuration
public class MyConfig {
@Lazy //延迟加载,调用此对象时才会去创建,默认不延迟加载
public User user() {
return new User("Lucifer", "xian", 18);
}
}
@Conditional
@Configuration
public class MyConfig {
@Scope("singleton")
@Lazy
@Bean
public User user() {
System.out.println("将对象user添加到容器中");
return new User("Lucifer", "xian", 18);
}
@Conditional(WindowsCondition.class)
@Bean
public User john() {
System.out.println("将John添加到容器中");
return new User("John", "xian", 17);
}
@Conditional(LinuxCondition.class)
@Bean
public User mandy() {
System.out.println("将mandy添加到容器中");
return new User("Mandy", "xian", 16);
}
}
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
System.out.println(osName);
if (osName.contains("Windows")) {
return true;
}
return false;
}
}
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
System.out.println(osName);
if (osName.contains("Linux")) {
return true;
}
return false;
}
}
@Test
public void test2() {
ApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println("IoC容器创建完成");
}
@Import
在一个Spring bean类上加@Import(value = User.class)去注入User对象
@Configuration
@Import(value = {User.class})
public class MyConfig {
public User user() {
return new User("Lucifer", "xian", 18);
}
}
给IoC容器注册Bean的方式:
1. 通过@Bean直接导入单个类
2. 通过@ComponentScan扫描包,默认扫描(@Controller, @Service, @Repository, @Component)
3. 通过@Import快速给容易导入Bean
3.1 通过@Import(User.class) 直接参数导入单个类
3.2 实现ImportSelector 自定义导入规则实现
3.3 实现ImportBeanDefinitionRegistrar,获得BeanDefinitionRegistry可以手动直接往IoC容器中注册Bean
4. 通过FactoryBean将bean注册到容器
通过ImportSelector自定义导入规则
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {"com.lucifer.project.model.Person"};
}
}
@Configuration
@Import(value = {User.class, MyImportSelector.class})
public class MyConfig {
public User user() {
return new User("Lucifer", "xian", 18);
}
}
通过ImportBeanDefinitionRegistrar往容器导入bean
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean person = registry.containsBeanDefinition("com.lucifer.project.model.Person");
if (person) {
BeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
registry.registerBeanDefinition("person", beanDefinition);
}
}
}
通过FactoryBean将bean注册到容器
public class MyFactoryBean implements FactoryBean<Animal> {
@Nullable
@Override
public Animal getObject() throws Exception {
return new Animal();
}
@Nullable
@Override
public Animal getObjectType() {
return Animal.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
@Import(value = {User.class, MyImportSelector.class})
public class MyConfig {
@Bean
public MyFactoryBean animal() {
return new MyFactoryBean();
}
}
public class MyTest {
@Test
public void test() {
ApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
Object obj= ac.getBean("animal");
System.out.println(obj.getClass()); // 打印的结果是com.lucifer.project.model.Animal
}
}
赋值(自动装配)组件
注解 | 说明 |
---|---|
@Component | 泛指组件,当组件不好归类的时候,使用这个注解进行标注 |
@Service | 用于标注业务层组件 |
@Controller | 用于标注控制层组件 |
@Repository | 用于标注数据访问层组件,即DAO组件 |
@Value | 普通数据类型赋值 |
@Autowired | 默认按类型装配,如果想按名称装配,可以结合@Qualifier注解一起使用 |
@PropertySource | 读取配置文件赋值 |
@Qualifier | 如存在多个实例,配合使用,优先级高于@Autowired |
@Primary | 自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 |
@Resource | 默认按名称装配,当找不到与名称匹配的Bean时才会按类型匹配 |
@Component
声明这个类需要被注册到IoC容器中
@Component
public class MyTypeFilter implements TypeFilter {}
@Service
如果是业务层组件,则用此注解,同样会被注册到IoC容器中
@Service
public class UserService {
@Autowired
UserDao userDao;
public User findById(String id) {
return userDao.findById(id);
}
public User update(User user) {
return userDao.update(user);
}
public void delete(String id) {
userDao.delete(id);
}
}
@Controller
如果是控制层组件,则用此注解,同样会被注册到IoC容器中
@Controller
public class UserController {}
@Repository
如果是数据访问层组件,则用此注解,同样会被注册到IoC容器中
@Repository
public class UserDao {
public User findById(String id) {
return null;
}
public User update(User user) {
return null;
}
public void delete(String id) {
}
}
@Value
public class User {
@Value("Lucifer") //支持基本数据类型
private String username;
@Value("${user.address}") //通过@PropertySource("classpath:values.properties")读取配置文件取值
private String address;
@Value("#{2021-1991}") //支持Spring EL表达式
private int age;
}
values.properties配置文件
user.address=SHAN'XI
@PropertySource
@Configuration
@PropertySource("classpath:values.properties")
public class MyConfig {
@Bean
public User user() {
System.out.println("将对象user添加到容器中");
return new User();
}
}
从环境变量Environment中取值
public class MyTest {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println("IoC容器创建完成");
String address = app.getBean("user.address");
// 从环境变量中取值
Environment env = app.getEnvironment();
env.getProperty("user.address");
}
}
@Autowired
默认按类型装配,如果想按名称装配,可以结合@Qualifier注解一起使用
@Controller
public class UserController {
@Autowired
UserService userService;
}
@Service
public class UserService {
@Autowired
UserDao userDao;
public User findById(String id) {
return userDao.findById(id);
}
public User update(User user) {
return userDao.update(user);
}
public void delete(String id) {
userDao.delete(id);
}
}
@Repository
public class UserDao {
public User findById(String id) {
return null;
}
public User update(User user) {
return null;
}
public void delete(String id) {
}
}
@Qualifier
如存在多个实例,配合@Autowired使用,优先级高于@Autowired,但是无法单独使用
@Configuration
public class MyConfig {
@Bean("userDao")
public UserDao userDao() {
return new UserDao();
}
}
@Service
public class UserService {
@Autowired
@Qualifier("userDao")
UserDao userDao;
}
@Resource
可以单独使用,优先级更高
@Service
public class UserService {
@Resource(name = "userDao")
UserDao userDao;
}
@Primary
如果Spring容器中存在多个相同名字的Bean,使用@Primary注解可以提高优先级,成为首选者,否则报错
@Configuration
public class MyConfig {
// 使用当前实例
@Primary
@Bean("userDao")
public UserDao userDao() {
return new UserDao();
}
@Bean("userDao")
public UserDao userDao2() {
return new UserDao();
}
}
织入组件
注解 | 说明 |
---|---|
ApplicationContextAware | 可以通过这个上下文环境对象得到Spring容器中的Bean |
BeanDefinitionRegistryPostProcessor | BeanDefinitionRegistryPostProcessor实现了BeanFactoryPostProcessor接口,是Spring框架的BeanFactoryRegistry的后处理器,用来注册额外的BeanDefinition |
切面组件
注解 | 说明 |
---|---|
@EnableTransactionManagement | 添加对事务管理的支持 |
@Transactional | 配置声明式事务信息 |