Spring中的Bean的注册有很多种方式,但大多区别不大,首先启动spring这个IOC容器的方式就有两种分别是古老的用*.xml文件来启动还有现在主流用注解式@Configuration声明一个为配置类来启动Spring容器。
首先说明:?得先大概会用Spring和SpringBoot(要不然可能会懵,只是可能会懵而已不用在意),因为SprinBoot里面就都是注解式开发
方式一(不推荐方式):? ??用xml文件里面的<Bean>标签声明注册 (用*.xml文件启动Spring)
xml文件代码:
<!--采用老式的<bean>标签方式声明注册对象,Person为一个实体类, id为person,
当spring容器启动时就会自己创建这个id=person的对象放到容器中-->
<bean id="person" class="com.entity.Person">
<property name="age" value="18"></property>
<property name="name" value="zhangsan"></property>
</bean>
测试代码:
//方式一: 通过 *.xml 配置文件方式创建,其中bean可以通过<bean>标签创建
//先根据*.xml文件启动spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//用id获取bean
Person person = (Person) applicationContext.getBean("person");
//输出获取的bean信息
System.out.println(person); //这个Person类重写了toString()方法可以输出对象的信息
控制台输出:??输出了person对象的消息,说明注册成功了
Person{name='zhangsan', age=18}
?方式二(不推荐方式,但SSM的话可以继续用):? ??用xml文件里面的<context:component-scan>包扫描标签声明注册 (还是用*.xml文件启动Spring)
xml文件代码:
<!--采用包扫描注解创建对象,扫描com.entity包下的所有类,这些类只要有
标注了@Controller,@Service,@Repository,@Component等都会被spring容器注册-->
<context:component-scan base-package="com.entity"></context:component-scan>
说明:??我的com.entity包下有3个类是加了@Component或Contorller注解的如下
@Controller
public class ControllerMy{具体代码省略...}
@Component
public class Person{具体代码省略...}
@Component
public class User{具体代码省略...}
测试代码:??
//方式二: 通过 *.xml 配置文件方式创建,其中bean可以通过<context:component-scan base-package="*">包扫描创建
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//获取所有已经被注册的bean的id名
String[] ids = applicationContext.getBeanDefinitionNames();
//输出
for(String name : ids){
System.out.println(name);
}
控制台输出(只截取了输出了有注解的bean的信息以下都同):? 有@Component或@Controller注解的类都被注册了
controllerMy person user
方式三(比起xml算是推荐方式吧,以下其他的方法都是用上注解了都是主流推荐方式):? ? 采用@Configuration注解声明配置类(取代了远古的xml文件方式) 启动spring容器,然后Bean的注册采用@Bean方式注册
@Configuration?配置类代码:
//@Configuration注解方式创建容器,bean通过@Bean创建
@Configuration
public class SpringConfiguration {
@Bean("person")//如果不给任何参数bean的id名默认为方法名
public Person getPerson(){
return new Person("lisi", 21); //实例一个对象交给spring容器管理
}
}
测试代码:??
//方式三: 通过@Configuration注解方式声明配置类创建 (通过com.config.SpringConfiguration配置类创建容器)
//bean通过直接在本配置类中用@Bean注解创建
ApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(SpringConfiguration.class);
//用类名获取bean
Person person2 = (Person) applicationContext2.getBean(Person.class);
//输出信息
System.out.println(person2);
控制台输出:?采用@Bean方式注册的bean成功输出
Person{name='xiaoli', age=40}
方式四(真正推荐方式):? ??采用@Configuration注解声明配置类,Bean采用@ComponentScan包扫描注解来注册的。
@Configuration?配置类代码:
//com.entity包下的所有有@Component,@Contorller等注解的类都会被注册到spring
@ComponentScan(value = "com.entity")
@Configuration
public class SpringConfiguration2 {
}
?说明:??我com.entity包下有3个类是加上了@Component等注解,?每个类的属性加@Value注解来注入具体的值
@Controller
public class ControllerMy{具体代码省略...}
@Component
public class Person{具体代码省略...}
@Component
public class User{具体代码省略...}
测试代码:
//方式四: 通过@Configuration注解方式声明配置类创建 (通过com.config.SpringConfiguration配置类创建容器)
//bean通过直接在本配置类中用@ComponentScan包扫描注解创建其他包的Bean
ApplicationContext applicationContext3 = new AnnotationConfigApplicationContext(SpringConfiguration2.class);
//获取所有的bean的id名
String[] ids = applicationContext3.getBeanDefinitionNames();
for(String s : ids){
System.out.println(s);
}
控制台输出:? 三个bean的id成功输出
controllerMy person user
Bean注册的注解扩展一:? ??@ComponentScan注解的一些其他特别用法
代码:? @ComponentScan?注解除了直接加要被扫描包的值外还可以添加一些其他的过滤条件值
@ComponentScan(value = "com.entity", excludeFilters = {@ComponentScan.Filter
(type = FilterType.ANNOTATION, classes = {Contorller.class})})
说明:?
?excludeFilters[]指的是排除要扫描的类
此@ComponentScan.Filter注解中说明了要排除被标记了为@Contoller的注解的类 excludeFilteres[]里的:
? ? FilterType.ANNOTATION:? 按照注解 FilterType.ASSIGNABLE_TYPE:按照给定的类型
? ? FilterType.ASPECTJ:? 按照ASPECTJ表达式 FilterType.REGEX:使用正则表达式? ? ? ? ? ? ? ? FilterType:CUSTOM:? 使用自定义规则 (得是TypeFilter的实现类)
除了excludeFilters是排除过滤,还有包含过滤,它们有很多的用法,读者可以自己去找它们专门的资料学习这里不在阐述。
Bean注册的注解扩展二:? ??@Lazy注解:? 懒加载注册bean
@Configuration 配置类代码:
@Configuration
public class SpringConfiguration4 {
/**
* @Lazy:
* 懒加载
* 单例Bean,默认在容器启动是创建对象
* 懒加载则是容器启动不创建对象,第一次使用(获取)Bean时才创建对象并初始化
*/
@Lazy
@Bean("person")
public Person getPerson(){
//如果spring启动时就注册了bean就会输出一下语句
System.out.println("容器创建了Person对象");
return new Person("虎哥", 12);
}
}
测试代码:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration4.class);
//情况一: 光启动容器不获取bean,bean不会被注册,控制台不会输出:
//情况二: 当要获取bean,bean才会被注册(这就是懒加载)。
Person person = (Person) applicationContext.getBean(Person.class);
控制台输出:? 如果是情况一没有任何输出,?如果是情况二会输出以下内容
容器创建了Person对象
Bean注册的注解扩展三:? ? @Conditional注解:?按照自己制定一系列的条件进行判断,满足条件就向容器中注册Bean
@Configuration?配置类代码:
@Configuration
public class SpringConfiguration5 {
/**
* @Conditional:
* 通过传入的MyCondition1.class条件类判断是否要创建此Bean
* (此条件类执行了判断本操作系统是否是Linux系统来决定是否要创建此Bean)
* (此注解要也可以放在类上,所有@Bean用同一个Condition.class类统一逐个判断是否要创建自己的Bean,Condition为接口需要自己实现这个接口)
*/
@Conditional(MyCondition1.class)//该MyCondition1类里面定义内如果我的环境是linux系统则注册此bean
@Bean("linux")
public Person getPerson1(){
return new Person("linus", 48);
}
/**
* @Conditional:
* 通过传入的MyCondition2.class条件类判断是否要创建此Bean
* (此条件类执行了判断本操作系统是否是windows系统来决定是否要创建此Bean
*/
@Conditional(MyCondition2.class)//该MyCondition2类里面定义内如果我的环境是Windows系统则注册此bean
@Bean("windows")
public Person getPerson2(){
return new Person("Bill Gates", 68);
}
}
MyCondition1和MyCondition2两个条件类的代码:
//自定义Condition类
//判断是否是Linux系统
public class MyCondition1 implements Condition {
/**
* @param conditionContext 判断条件能使用的上下文(环境)
* @param annotatedTypeMetadata 注释信息
* @return
*/
//此方法返回true则注册否则不注册bean
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取到ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
conditionContext.getClassLoader();
//获取当前环境信息
Environment environment = conditionContext.getEnvironment();
//获取Bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
//获取操作系统名
String property = environment.getProperty(("os.name"));
if(property.contains("linux")){ //判断是否匹配
return true;
}
return false;
}
}
//自定义Condition类
//判断是否是Linux系统
public class MyCondition2 implements Condition {
/**
* @param conditionContext 判断条件能使用的上下文(环境)
* @param annotatedTypeMetadata 注释信息
* @return
*/
//此方法返回true则注册否则不注册bean
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//获取到ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
conditionContext.getClassLoader();
//获取当前环境信息
Environment environment = conditionContext.getEnvironment();
//获取Bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
//获取操作系统名
String property = environment.getProperty(("os.name"));
if(property.contains("Windows")){ //判断是否匹配
return true;
}
return false;
}
}
测试代码:
@Test
public void test04(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration5.class);
//获取容器中所有已经被注册的bean的id
String[] names = applicationContext.getBeanDefinitionNames();
//输出
for(String s : names){
System.out.println(s);
}
}
控制台输出:? 因为我的环境是Windows系统,所以果不其然输出为windows(此bean的id)
windows
?Bean注册的注解扩展四:? ? @Import注解,容器会按照注解里声明的类自动创建Bean (被注册的Bean的id默认为类的全限定名)
@Configuration?配置类代码:
/**
* @Import: 导入式的注册创建beand
* 容器会自动注册创建这个注解里的参数类的Bean
* (被注册的Bean的id默认为全限定类名)
*/
@Import({Color.class, Employee.class}) //只有这两个类会被注册
@Configuration
public class SpringConfiguration6 {
}
测试代码:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration6.class);
//获取所有bean的id
String[] names = applicationContext.getBeanDefinitionNames();
//输出
for(String s : names){
System.out.println(s);
}
控制台输出:?输了了Color和Employee类的全限定名? ? ? ?
com.entity.Color com.entity.Employee
@Import还有很多其他五花八门的用法以及其他的注解,如果想要彻底掌握可以去查阅专门资料。
END:?累了累了,还有其他注解用法之后再补充
|