bean 的作用域
①The Singleton Scope
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
②The Prototype Scope
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
bean 的自动装配
在Spring中有三种装配方式:
①在xml中显式地装配
②在java 显式地装配
③隐式地自动装配(重点)
1.byName 的自动装配
2.byType 的自动装配
Spring 注解实现自动装配
要使用注解需要知道:
- 导入约束 context
- 配置注解的支持
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
-
默认按照类型去找对应得组件:applicationContext.getBean(BookDao.class);
-
如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找。applicationContext.getBean(“bookDao”);
-
直接在属性上使用即可,也可以在set()方法,构造器,参数使用。 如果只有一个有参构造器,那么这个有参构造
器的Autowired 可以省略,从容器中自动装配。 -
使用@Autowired 我们可以不用有set()方法,但前提条件是自动装配的属性在ioc容器中已经存在,且符合byName规则。
-
自动装配一定要将属性赋值好,@Autowired(”required=false“) 可以允许属性值为null.
-
@bean 标注的方法创建对象的时候,方法参数默认从容器中获取。
@Qulified(value=“xxxx”)
如果Autowired 自动装配的环境比较复杂,那么我们可以用这个来配合Autowired 来使用,确定唯一的bean 对象注入。
@Primary
让Spring 进行自动装配的时候,默认首选的bean,此时@Qulified(value=“xxxx”)不能同时使用了
拓展
@Nullable
字段标记了这个注解,说明这个注解可以为null.
Spring 还支持 @Resource 和@Inject
@Resource
- 可以像@Autowired 一样自动装配,默认是按照属性的名称作为id去装配组件,@Resource(name=“xxxx”)来指定id去装配。
- 不能支持@Primary 功能,也不支持@Autowired(”required=false“)
@Inject
需要导入javax.inject 依赖,和@Autowired功能一样,但不支持@Autowired(”required=false“)的注解。
Spring 注解实现-- 组件注册
@Configuration
告诉spring这是一个配置类,相当于xml方式中的 <beans> </beans>
@Bean
向容器中注册一个组件,类型默认是返回值类型,id默认是方法名作为id.
@Bean
public Person person(){
return new Person("KKK", 25);
}
@Bean(“person”) 指定bean 的id.
@ComponentScan //不写参数,则默认扫本类下的包及子包
@ComponentScan(“cn.fg2”) //jdk8支持写多个@ComponentScan,源码里面有个@Repeatable
@ComponentScan(value="cn.fg",includeFilters={ //包扫描
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
},excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Service.class})
},useDefaultFilters=false)
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型 @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class})
//FilterType.CUSTOM:使用自定义规则
等同于
<context:component-scan base-package="cn.fg">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exinclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
自定义TypeFilter指定过滤规则
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();
System.out.println("---" + className);
/*if (className.contains("er")){
return true;
}*/
return false;
}
}
@Scope(“prototype”) 多例的bean,默认是多实例的bean
@Conditional(LinuxCondition.class)
必须满足条件后,bean才会被创建,该注解也可以用在类上
package cn.fg.demo.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 { //需要实现Condition接口
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息,可以获取到注解标注在所在类的或所在方法上的其他注解的信息,这里传进来的是StandardAnnotationMetadata,应用场景搜百度
*/
@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;
}
@Import给容器中快速导入组件
public class TestImport {
}
/**
* 配置类,代替配置文件
*/
@Configuration //告诉Spring这是一个配置类
@Import(TestImport.class)
public class MainConfig {
@Bean("person")
public Person person(){
return new Person("KKK", 25);
}
}
ImportSelector: 返回需要导入的组件的全类名数组。springBoot常用
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.bjtu.bean.Blue","com.bjtu.bean.Red"};
}
}
@Import({TestImport.class, MyImportSelector.class})
public class MainConfig {
@Bean("person")
public Person person(){
return new Person("KKK", 25);
}
}
ImportBeanDefinitionRegistrar:手动注册bean到容器中
//创建一个spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean.....getObject....");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
//是单例?
//true,这个bean是个单实例,在容器中保存一份
//false,多实例,每次获取都会创建一个新实例
@Override
public boolean isSingleton() {
return false;
}
}
@Test
public void ImportTest(){
//工厂Bean获取的是调用getObject创建的对象
//多实例的Bean每创建一次对象就调用一次getObject()方法
Object bean1 = applicationContext.getBean("colorFactoryBean");
Object bean2 = applicationContext.getBean("colorFactoryBean");
System.out.println("bean1的类型是:"+bean1.getClass());
System.out.println(bean1 == bean2);
System.out.println("***********************");
//加上“&”获取的就是获取工厂本身
Object bean3 = applicationContext.getBean("&colorFactoryBean");
System.out.println(bean3);
}
Spring 注解 属性赋值
@Value赋值
1). 基本数值
2). 可以使用SpEL:#{}
3). 可以写${},取出配置文件【properties】中的值(在运行环境变量里面的值)
注:对于idea来说,它的路径resourse默认到文件,所以只需要文件名就只可以获取到里面的值
public class Person {
//1.基本数值
@Value("张三")
private String name;
//2.SpEL:#{}
@Value("#{18-2}")
private Integer age;
//取出配置文件properties中的值
@Value("${person.nickName}")
private String nickName;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", nickName='" + nickName + '\'' +
'}';
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public Person() {
}
}
//使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中
// 加载完外部的配置文件以后使用${}取出配置文件的值
@PropertySource(value = {"person.properties"})
@Configuration //声明配置类
public class MainConfigOfProperty {
@Bean//注册一个组件
public Person person(){
return new Person();
}
}
//测试方法
public class IocTestPropertyValue {
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProperty.class);
printBean(applicationContext);
System.out.println("-------------------------");
Person person = (Person)applicationContext.getBean("person");
System.out.println(person);
//运行时的环境变量
//这是第二种获得配置文件中的值的方式
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String property = environment.getProperty("person.nickName");
System.out.println(property);
//关闭容器
applicationContext.close();
}
private void printBean(AnnotationConfigApplicationContext applicationContext){
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}