Spring常用注解

本文介绍一些 Spring 中常用注解的使用方式。

@Configuration声明配置类

@Configuration用来申明一个配置类,相当于写了一个配置文件。我们可以使用 Spring 的容器 AnnotationConfigApplicationContext 可以加载这个配置来获取 Bean。

Spring 中有两种容器 AnnotationConfigApplicationContext 是我们使用注解方式进行配置时使用的容器,ClassPathXmlApplicationContext 是我们使用 xml 方式进行配置时使用的容器。

接下来,举例说明如何使用这两种方式。

XML 方式进行配置

最开始的时候我们使用 xml 的方式来配置 bean,然后用ClassPathXmlApplicationContext 初始化容器:

1
2
3
4
5
6
7
8
9
10
<?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="person" class="com.enjoy.cap1.Person">
		<property name="name" value="james"></property>
		<property name="age" value="19"></property>
	</bean>
</beans>
1
2
3
4
5
6
7
8
9
10
public class MainTest1 { 
	public static void main(String args[]){
		// 加载 beans.xml
		ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
		// 获取 bean
		Person person = (Person) app.getBean("person");
		
		System.out.println(person);
	}
}

注解方式进行配置

使用 @Configuration 注解来申明一个配置类,接着使用 AnnotationConfigApplicationContext 来初始化容器。

1
2
3
4
5
6
7
@Configuration
public class MainConfig {
	@Bean
	public Person person(){
		return new Person("james",20);
	}
}
1
2
3
4
5
6
7
8
9
10
11
public class MainTest2 { 
	public static void main(String args[]){
		
		ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
		
		String[] namesForBean = app.getBeanNamesForType(Person.class);
		for(String name:namesForBean){
			System.out.println(name);
		}
	}
}

@ComponentScan 扫描规则

@ComponentScan会去扫描 @Component@Controller@Service@Respostry注解的类。同时,它也可以指定扫描范围、配置扫描过滤器、自定义扫描规则。

  • 指定扫描范围,使用 value="com.shuiyujie.xxx"
  • 配置扫描过滤器,通过 includeFilters 来指定扫描哪些类,excludeFilters 来指定不扫描哪些类。指定时要配置 @FilteruseDefaultFilters 参数。
  • 自定义扫描规则,自定义一个类实现 TypeFilter 接口,自定义过滤规则。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
/**
 * FilterType 有多种类型:
 * - ANNOTATION,
 * - ASSIGNABLE_TYPE,
 * - ASPECTJ,
 * - REGEX,
 * - CUSTOM;
 */
@ComponentScan(value="com.enjoy.cap2", includeFilters={		
		@Filter(type=FilterType.CUSTOM, classes={JamesTypeFilter.class})		
}, useDefaultFilters=false)

public class Cap2MainConfig {
	@Bean
	public Person person01(){
		return new Person("james",20);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class JamesTypeFilter implements TypeFilter{
	private ClassMetadata classMetadata;

	/*
	 * MetadataReader:读取到当前正在扫描类的信息
	 * MetadataReaderFactory:可以获取到其他任何类信息
	 */
	
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		//获取当前类注解的信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前正在扫描的类信息
		classMetadata = metadataReader.getClassMetadata();
		//获取当前类资源(类的路径)
		Resource resource = metadataReader.getResource();
		
		String className = classMetadata.getClassName();
		System.out.println("----->"+className);
		if(className.contains("order")){//当类包含er字符, 则匹配成功,返回true
			return true;
		}
		return false;
	}

}

@Scope 指定 Bean 的作用域范围

给容器中注册一个 Bean, 类型为返回值的类型, 默认是单例。singleton 是默认创建 Bean 的方式,它会在 Spring 容器初始化的时候就创建 Bean,这个 Bean 有且只会创建这样一次。prototype 则不会在 Spring 容器初始化的时候创建,而是在使用这个 Bean (比如getBean())的时候实例化化一个 Bean。

  • prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
  • singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
  • request: 主要针对web应用, 递交一次请求创建一个实例
  • session:同一个session创建一个实例
1
2
3
4
5
6
7
8
@Configuration
public class Cap3MainConfig {
	@Scope("prototype")
	@Bean
	public Person person(){
		return new Person("james",20);
	}
}

@Lazy 懒加载

我们知道 Bean 默认是 Singleton 的,它会在容器启动的时候就创建这个对象。如果我们不希望 Singleton 的 Bean 在容器初始化的时候就创建,而是希望它在使用对象的时候创建,就可以使用懒加载的方式,具体来说就是在 Bean 上添加 @Lazy

1
2
3
4
5
6
7
8
9
@Configuration
public class Cap4MainConfig {
	@Lazy
	@Bean
	public Person person(){
		System.out.println("给容器中添加person.......");
		return new Person("james",20);
	}
}

@Conditional条件注册bean

添加@Conditional的 Bean 可以自定义加载条件,比如说在不同的操作系统中加载不同的 Bean。关键在于配置的类需要实现 Condition 接口,接着可以在 matches() 中获取到更多信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
public class Cap5MainConfig {
	@Bean("person")
	public Person person(){
		System.out.println("给容器中添加person.......");
		return new Person("person",20);
	}
	
	@Conditional(WinCondition.class)
	@Bean("lison")
	public Person lison(){
		System.out.println("给容器中添加lison.......");
		return new Person("Lison",58);
	}
  
	@Conditional(LinCondition.class)
	@Bean("james")//bean在容器中的ID为james, IOC容器MAP,  map.put("id",value)
	public Person james(){
		System.out.println("给容器中添加james.......");
		return new Person("james",20);
	}
}

WinCondition 实现了 Condition 接口,通过 context 获取操作系统信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class WinCondition implements Condition{	
	/*
	* ConditionContext: 判断条件可以使用的上下文(环境)
	* AnnotatedTypeMetadata: 注解的信息
	*/
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO 是否为WINDOW系统
		//能获取到IOC容器正在使用的 beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
		Environment environment = context.getEnvironment();
		String os_name = environment.getProperty("os.name");
		if(os_name.contains("Windows")){
			return true;
		}
		return false;
	}

}

@Import注册 Bean

在容器中注册组件的方式有:

  1. @Bean,导入第三方的类或包的组件,比如说我们自己定义一个 Person 类
  2. 包扫描+组件注解,即@ComponentScan+Component@Controller@Service@Reponsitory,一般用于我们自己写的类
  3. @Import快速给容器导入一个类,能做比@Bean更加复杂的操作
    1. @Import 要导入到容器中的组件):容器会自动注册这个组件,bean 的 id为全类名
    2. ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
    3. ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
  4. 使用Spring提供的FactoryBean(工厂bean)进行注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
@Import(value = { Dog.class,Cat.class,                
				JamesImportSelector.class,JamesImportBeanDefinitionRegistrar.class })
public class Cap6MainConfig {
	/*
	 * 给容器中注册组件的方式
	 * 1,@Bean: [导入第三方的类或包的组件],比如Person为第三方的类, 需要在我们的IOC容器中使用
	 * 2,包扫描+组件的标注注解(@ComponentScan:  @Controller, @Service  @Reponsitory  @ Componet),一般是针对 我们自己写的类,使用这个
	 * 3,@Import:[快速给容器导入一个组件] 注意:@Bean有点简单
	 *      a,@Import(要导入到容器中的组件):容器会自动注册这个组件,bean 的 id为全类名
	 *      b,ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
	 *      c,ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
	 *          写JamesImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
	 *  4,使用Spring提供的FactoryBean(工厂bean)进行注册
	 *     
	 *   
	 */
	//容器启动时初始化person的bean实例
	@Bean("person")
	public Person person(){
		return new Person("james",20);
	}
	@Bean
	public JamesFactoryBean jamesFactoryBean(){
		return new JamesFactoryBean();
	}
}
1
2
3
4
5
6
7
public class JamesImportSelector implements ImportSelector{
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata){
		//返回全类名的bean
		return new String[]{"com.enjoy.cap6.bean.Fish","com.enjoy.cap6.bean.Tiger"};
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/*
	*AnnotationMetadata:当前类的注解信息
	*BeanDefinitionRegistry:BeanDefinition注册类
	*    把所有需要添加到容器中的bean加入;
	*    @Scope
	*/
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean bean1 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Dog");
		boolean bean2 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Cat");
		//如果Dog和Cat同时存在于我们IOC容器中,那么创建Pig类, 加入到容器
		//对于我们要注册的bean, 给bean进行封装,
		if(bean1 && bean2){
			RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
			registry.registerBeanDefinition("pig", beanDefinition);
		}
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class JamesFactoryBean implements FactoryBean<Monkey>{

	@Override
	public Monkey getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Monkey();
	}

	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Monkey.class;
	}
	
	@Override
	public boolean isSingleton() {
		return true;
	}
}
原文地址:https://www.cnblogs.com/shuiyj/p/13185100.html