Spring注解驱动开发-----组件注册
Posted alimayun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring注解驱动开发-----组件注册相关的知识,希望对你有一定的参考价值。
注册bean
xml方式
1、beans.xml-----很简单,里面注册了一个person bean
<?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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <bean id="person" class="com.atguigu.bean.Person"> <property name="age" value="18"></property> <property name="name" value="zhangsan"></property> </bean> </beans>
2、person
package com.atguigu.bean; import org.springframework.beans.factory.annotation.Value; public class Person private String name; private Integer age; public String getName() return name; public void setName(String name) this.name = name; public Integer getAge() return age; public void setAge(Integer age) this.age = age; public Person(String name, Integer age) super(); this.name = name; this.age = age; public Person() super(); @Override public String toString() return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
3、MainTest-----测试类
package com.atguigu; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.atguigu.bean.Person; import com.atguigu.config.MainConfig; public class MainTest @SuppressWarnings("resource") public static void main(String[] args) ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Person bean = (Person) applicationContext.getBean("person"); System.out.println(bean);
测试结果:
注解方式
1、MainConfig-----配置类
@Configuration //告诉Spring这是一个配置类 //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") public Person person01() return new Person("lisi", 20);
2、MainTest
package com.atguigu; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.atguigu.bean.Person; import com.atguigu.config.MainConfig; public class MainTest @SuppressWarnings("resource") public static void main(String[] args) ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Person bean = applicationContext.getBean(Person.class); System.out.println(bean); String[] namesForType = applicationContext.getBeanNamesForType(Person.class); for (String name : namesForType) System.out.println(name);
3、@Configuration-----可以看出是继承了@Component
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration @AliasFor(annotation = Component.class) String value() default "";
自动扫描
xml方式
1、beans.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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <context:component-scan base-package="com.atguigu"></context:component-scan> <bean id="person" class="com.atguigu.bean.Person"> <property name="age" value="18"></property> <property name="name" value="zhangsan"></property> </bean> </beans>
注解方式
1、MainConfig
package com.atguigu.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.ComponentScans; import com.atguigu.bean.Person; //配置类==配置文件 @Configuration //告诉Spring这是一个配置类 @ComponentScan(value="com.atguigu") //value:指定要扫描的包 public class MainConfig //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id @Bean("person") public Person person01() return new Person("lisi", 20);
2、BookController
package com.atguigu.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import com.atguigu.service.BookService; @Controller public class BookController @Autowired private BookService bookService;
3、BookService
package com.atguigu.service; import javax.annotation.Resource; import javax.inject.Inject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import com.atguigu.dao.BookDao; @Service public class BookService @Autowired(required=false) private BookDao bookDao; public void print() System.out.println(bookDao); @Override public String toString() return "BookService [bookDao=" + bookDao + "]";
4、BookDao
package com.atguigu.dao; import org.springframework.stereotype.Repository; //名字默认是类名首字母小写 @Repository public class BookDao private String lable = "1"; public String getLable() return lable; public void setLable(String lable) this.lable = lable; @Override public String toString() return "BookDao [lable=" + lable + "]";
5、IocTest
package com.atguigu.test; import java.util.Map; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import com.atguigu.bean.Blue; import com.atguigu.bean.Person; import com.atguigu.config.MainConfig; import com.atguigu.config.MainConfig2; public class IOCTest @SuppressWarnings("resource") @Test public void test01() AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) System.out.println(name);
@ComponentScan
1、excludeFilters
@ComponentScan(value="com.atguigu",excludeFilters = @Filter(type=FilterType.ANNOTATION,classes=Controller.class,Service.class))
排除controller以及service,不允许注册。
2、includeFilters
@ComponentScan(value="com.atguigu",includeFilters = @Filter(type=FilterType.ANNOTATION,classes=Controller.class),useDefaultFilters=false)
只扫描controller。-----需要添加useDefaultFilters=false
@ComponentScans
@ComponentScans( value = @ComponentScan(value="com.atguigu",includeFilters = @Filter(type=FilterType.ANNOTATION,classes=Controller.class) ,useDefaultFilters = false) )
其实就是可以定义多个扫描策略。
TypeFilter
- @ComponentScan value:指定要扫描的包
- excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
- includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
- FilterType.ANNOTATION:按照注解
- FilterType.ASSIGNABLE_TYPE:按照给定的类型;
- FilterType.ASPECTJ:使用ASPECTJ表达式
- FilterType.REGEX:使用正则指定
- FilterType.CUSTOM:使用自定义规则
其中注解最为常见。
设置组件作用域
@Scope
spring中默认都是单例bean,不过也可以通过@Scope进行设置。
1、MainConfig2
package com.atguigu.config; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import com.atguigu.bean.Blue; import com.atguigu.bean.Color; import com.atguigu.bean.ColorFactoryBean; import com.atguigu.bean.Person; import com.atguigu.bean.Red; import com.atguigu.condition.LinuxCondition; import com.atguigu.condition.MyImportBeanDefinitionRegistrar; import com.atguigu.condition.MyImportSelector; import com.atguigu.condition.WindowsCondition; import com.atguigu.test.IOCTest; @Configuration public class MainConfig2 //默认是单实例的 /** * ConfigurableBeanFactory#SCOPE_PROTOTYPE * @see ConfigurableBeanFactory#SCOPE_SINGLETON * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION sesssion * @return * @Scope:调整作用域 * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。 * 每次获取的时候才会调用方法创建对象; * singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。 * 以后每次获取就是直接从容器(map.get())中拿, * request:同一次请求创建一个实例 * session:同一个session创建一个实例 */ @Scope("prototype") @Bean("person") public Person person() System.out.println("给容器中添加Person...."); return new Person("张三", 25);
2、IocTest
package com.atguigu.test; import java.util.Map; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import com.atguigu.bean.Blue; import com.atguigu.bean.Person; import com.atguigu.config.MainConfig; import com.atguigu.config.MainConfig2; public class IOCTest @Test public void test02() AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); System.out.println("ioc容器创建完成...."); Object bean = applicationContext.getBean("person"); Object bean2 = applicationContext.getBean("person"); System.out.println(bean == bean2);
3、测试结果
@Lazy-----只针对于singleton模式
package com.atguigu.config; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import com.atguigu.bean.Blue; import com.atguigu.bean.Color; import com.atguigu.bean.ColorFactoryBean; import com.atguigu.bean.Person; import com.atguigu.bean.Red; import com.atguigu.condition.LinuxCondition; import com.atguigu.condition.MyImportBeanDefinitionRegistrar; import com.atguigu.condition.MyImportSelector; import com.atguigu.condition.WindowsCondition; import com.atguigu.test.IOCTest; @Configuration public class MainConfig2 //默认是单实例的 /** * 懒加载: * 单实例bean:默认在容器启动的时候创建对象; * 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化; * */ @Scope("singleton") @Lazy @Bean("person") public Person person() System.out.println("给容器中添加Person...."); return new Person("张三", 25);
@Conditional-----按照一定的条件进行判断,满足条件给容器中注册bean
配置在方法上
示例:根据是windows还是linux系统,判断person为Bill还是Linus
1、MainConfig
package com.atguigu.config; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import com.atguigu.bean.Blue; import com.atguigu.bean.Color; import com.atguigu.bean.ColorFactoryBean; import com.atguigu.bean.Person; import com.atguigu.bean.Red; import com.atguigu.condition.LinuxCondition; import com.atguigu.condition.MyImportBeanDefinitionRegistrar; import com.atguigu.condition.MyImportSelector; import com.atguigu.condition.WindowsCondition; import com.atguigu.test.IOCTest; @Configuration public class MainConfig2 /** * @Conditional(Condition) : 按照一定的条件进行判断,满足条件给容器中注册bean * * 如果系统是windows,给容器中注册("bill") * 如果是linux系统,给容器中注册("linus") */ @Conditional(WindowsCondition.class) @Bean("bill") public Person person01() return new Person("Bill Gates",62); @Conditional(LinuxCondition.class) @Bean("linus") public Person person02() return new Person("linus", 48);
2、LinuxCondition
package com.atguigu.condition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; //判断是否linux系统 public class LinuxCondition implements Condition /** * ConditionContext:判断条件能使用的上下文(环境) * AnnotatedTypeMetadata:注释信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) // TODO是否linux系统 //1、能获取到ioc使用的beanfactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); //2、获取类加载器 ClassLoader classLoader = context.getClassLoader(); //3、获取当前环境信息 Environment environment = context.getEnvironment(); //4、获取到bean定义的注册类 BeanDefinitionRegistry registry = context.getRegistry(); String property = environment.getProperty("os.name"); //可以判断容器中的bean注册情况,也可以给容器中注册bean boolean definition = registry.containsBeanDefinition("person"); if(property.contains("linux")) return true; return false;
3、WindowsCondition
package com.atguigu.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; //判断是否windows系统 public class WindowsCondition implements Condition @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if(property.contains("Windows")) return true; return false;
4、IOCTest
package com.atguigu.test; import java.util.Map; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import com.atguigu.bean.Blue; import com.atguigu.bean.Person; import com.atguigu.config.MainConfig; import com.atguigu.config.MainConfig2; public class IOCTest @Test public void test03() String[] namesForType = applicationContext.getBeanNamesForType(Person.class); ConfigurableEnvironment environment = applicationContext.getEnvironment(); //动态获取环境变量的值;Windows 10 String property = environment.getProperty("os.name"); System.out.println(property); for (String name : namesForType) System.out.println(name); Map<String, Person> persons = applicationContext.getBeansOfType(Person.class); System.out.println(persons);
运行结果:
由于当前系统是win10,所以只有Bill对象存在。
那么如何试验得到Linus呢?
通过run configuration的-Dos.name,直接更改jvm参数,然后eviroment中取os.name就为linux了。
配置在类上
MainConfig
package com.atguigu.config; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import com.atguigu.bean.Blue; import com.atguigu.bean.Color; import com.atguigu.bean.ColorFactoryBean; import com.atguigu.bean.Person; import com.atguigu.bean.Red; import com.atguigu.condition.LinuxCondition; import com.atguigu.condition.MyImportBeanDefinitionRegistrar; import com.atguigu.condition.MyImportSelector; import com.atguigu.condition.WindowsCondition; import com.atguigu.test.IOCTest; //类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效; @Conditional(WindowsCondition.class) @Configuration public class MainConfig2 /** * @Conditional(Condition) : 按照一定的条件进行判断,满足条件给容器中注册bean * * 如果系统是windows,给容器中注册("bill") * 如果是linux系统,给容器中注册("linus") */ @Bean("bill") public Person person01() return new Person("Bill Gates",62); @Conditional(LinuxCondition.class) @Bean("linus") public Person person02() return new Person("linus", 48);
给容器快速导入一个组件
给容器注册组件的方式
1、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
2、@Bean[导入的第三方包里面的组件]
3、@Import[快速给容器中导入一个组件]
- a、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
- b、ImportSelector:返回需要导入的组件的全类名数组;
- c、ImportBeanDefinitionRegistrar:手动注册bean到容器中
4、使用Spring提供的 FactoryBean(工厂Bean);
- a、默认获取到的是工厂bean调用getObject创建的对象
- b、要获取工厂Bean本身,我们需要给id前面加一个 && colorFactoryBean
@Import
@Configuration //@Import导入组件,id默认是组件的全类名 @Import(Color.class,Red.class) public class MainConfig2
ImportSelector-----实现这个接口(将需要导入的组件放入数组中)
1、MyImportSelector
package com.atguigu.condition; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; //自定义逻辑返回需要导入的组件 public class MyImportSelector implements ImportSelector //返回值,就是到导入到容器中的组件全类名 //AnnotationMetadata:当前标注@Import注解的类的所有注解信息 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) // TODO Auto-generated method stub //importingClassMetadata //方法不要返回null值 return new String[]"com.atguigu.bean.Blue","com.atguigu.bean.Yellow";
2、MainConfig
package com.atguigu.config; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import com.atguigu.bean.Blue; import com.atguigu.bean.Color; import com.atguigu.bean.ColorFactoryBean; import com.atguigu.bean.Person; import com.atguigu.bean.Red; import com.atguigu.condition.LinuxCondition; import com.atguigu.condition.MyImportBeanDefinitionRegistrar; import com.atguigu.condition.MyImportSelector; import com.atguigu.condition.WindowsCondition; import com.atguigu.test.IOCTest; @Configuration @Import(MyImportSelector.class) public class MainConfig2
ImportBeanDefinitionRegistrar-----实现这个接口(创建BeanDefinition,通过BeanDefinitionRegistry.registerBeanDefinition()导入)
1、MyImportBeanDefinitionRegistrar
package com.atguigu.condition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; import com.atguigu.bean.RainBow; public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar /** * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类; * 把所有需要添加到容器中的bean;调用 * BeanDefinitionRegistry.registerBeanDefinition手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red"); boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue"); if(definition && definition2) //指定Bean定义信息;(Bean的类型,Bean。。。) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); //注册一个Bean,指定bean名 registry.registerBeanDefinition("rainBow", beanDefinition);
2、MainConfig2
package com.atguigu.config; import org.springframework.context.annotation.Configuration; import com.atguigu.condition.MyImportBeanDefinitionRegistrar; @Configuration @Import(MyImportBeanDefinitionRegistrar.class) //@Import导入组件,id默认是组件的全类名 public class MainConfig2
FactoryBean-----实现spring提供的这个工厂bean
1、ColorFactoryBean
package com.atguigu.bean; import org.springframework.beans.factory.FactoryBean; //创建一个Spring定义的FactoryBean public class ColorFactoryBean implements FactoryBean<Color> //返回一个Color对象,这个对象会添加到容器中 @Override public Color getObject() throws Exception // TODO Auto-generated method stub System.out.println("ColorFactoryBean...getObject..."); return new Color(); @Override public Class<?> getObjectType() // TODO Auto-generated method stub return Color.class; //是单例? //true:这个bean是单实例,在容器中保存一份 //false:多实例,每次获取都会创建一个新的bean; @Override public boolean isSingleton() // TODO Auto-generated method stub return false;
2、MainConfig2
package com.atguigu.config; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import com.atguigu.bean.Blue; import com.atguigu.bean.Color; import com.atguigu.bean.ColorFactoryBean; import com.atguigu.bean.Person; import com.atguigu.bean.Red; import com.atguigu.condition.LinuxCondition; import com.atguigu.condition.MyImportBeanDefinitionRegistrar; import com.atguigu.condition.MyImportSelector; import com.atguigu.condition.WindowsCondition; import com.atguigu.test.IOCTest; @Configuration public class MainConfig2 /** * 给容器中注册组件; * 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类] * 2)、@Bean[导入的第三方包里面的组件] * 3)、@Import[快速给容器中导入一个组件] * 1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名 * 2)、ImportSelector:返回需要导入的组件的全类名数组; * 3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中 * 4)、使用Spring提供的 FactoryBean(工厂Bean); * 1)、默认获取到的是工厂bean调用getObject创建的对象 * 2)、要获取工厂Bean本身,我们需要给id前面加一个& * &colorFactoryBean */ @Bean public ColorFactoryBean colorFactoryBean() return new ColorFactoryBean();
注:虽然@Bean的是ColorFactoryBean,但是其实是将此工厂内的bean注册到容器中。如果要获取工厂bean本身,getBean("&..."),在名称前加“&”。
以上是关于Spring注解驱动开发-----组件注册的主要内容,如果未能解决你的问题,请参考以下文章
Spring注解驱动开发在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean