• 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;
    	}
    }
    
  • 相关阅读:
    Windows 程序员必备的知识和工具
    由级别和性格特征将程序员分类 看看你属于哪一种
    调试九法:软硬件错误的排查之道<书评>
    逆向反汇编代码推算C++的局部变量
    逆向分析一个完整的C++程序包含寄存器与参数传递详解
    1607:Unable to install InstallShield Scripting runtime
    Form的构造函数和Load事件的区别?
    "春运男子持刀强行劫走17张卧铺票" ....
    SQL SERVER 2005中的Case When用法
    SBO中各个版本的密码
  • 原文地址:https://www.cnblogs.com/shuiyj/p/13185100.html
Copyright © 2020-2023  润新知