# 一、核心容器

【1】@Configuration:告诉 Spring 这是一个配置类(配置类=配置文件)
【2】@Bean:给容器中注册一个Bean ;类型为返回值类型,id 默认是用方法名作为 id 也可以通过 value 属性添加 id(相当于 xml 中的<bean>标签),主要用于导入第三方包里面的组件。
【3】@ComponentScan:包扫描,只要标注了 @Cotroller@Service@Repository@Componet 等注解便会自动注入此类,excludeFilters属性可以定义需要排除的注解或者类,通过@Filter数组进行定义,type属性为类型(注解、类、正则、自定义的TypeFilter等等)class为排除的类或注解类。includeFilters属性指定只需要扫描包含的注解或者类,但需要关闭默认的扫描包注解的规则:useDefaultFilters=false默认为true。主要用于导入自己定义的组件。

@Configuration
@ComponentScan(value="com.atyintong"/*,excludeFilters= {
        @Filter(type=FilterType.ANNOTATION,classes={Controller.class,Service.class})
},useDefaultFilters=false,includeFilters= {
        @Filter(type=FilterType.ANNOTATION,classes=Service.class)
}*/)
public class MainConfig {
    @Bean
    public Person persion() {
        return new Person("zzx",12);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

【4】获取配置文件的方式:new AnnotationConfigApplicationContext(MainConfig.class)

AnnotationConfigApplicationContext application=new AnnotationConfigApplicationContext(MainConfig.class);
@Test
public void test() {
    Person person = application.getBean(Person.class);
    System.out.println(person);
}
/*输入内容如下:Person [name=zzx, age=12, nickName=null]*/
1
2
3
4
5
6
7

【5】@scope:默认为singleton表示单实例,容器启动时调用方法创建对象放到ioc容器中,以后每次调用时直接从中获取。常用的还有prototype表示多实例,容器启动时不创建对象,每当调用时才创建当前对象。

@Scope(value="prototype")
@Bean
public Person persion() {
1
2
3

【6】@lazy:懒加载,单实例bean默认在容器启动时不创建对象,第一次获取对象的时候创建对象。以后调用不再创建对象。
【7】@Conditonal({Condition}):按照一定条件进行判断,放在配置类的方法上表示,满足条件才给容器注册bean。也可以放在类上表示,满足条件才执行配置类。首先需要自定义一个实现Condition接口的类,如下:

public class TestCondition implements Condition{

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 1、context:判断条件能使用的上下文环境
        // 2、metadata:注释信息
        // 1.1 获取当前环境信息
        Environment environment = context.getEnvironment();
        // 1.2 获取bean的注册类信息
        BeanDefinitionRegistry registry = context.getRegistry();
        String property = environment.getProperty("os.name");
        if(property.contains("Windows") && !registry.containsBeanDefinition("person")) {
            return true;
        }
        return false;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

在配置内中加载两个不同的Persion对象,并在person01对象加载方法前加入@Conditional注解,查看是否加载此对象。

@Bean
public Person person() {
    return new Person("zzx",12);
}

@Conditional(TestCondition.class)
@Bean("person01")
public Person person01() {
    return new Person("lisi",13);
}
/* IOC 容器启动时,不包含person01 对象,因为Conditional 条件返回为 false */
1
2
3
4
5
6
7
8
9
10
11

【8】@Import:导入组件,id默认是组件的全类名。

@Import({Cat.class,MyImportSelector.class})  //输出的结果为:com.atyintong.bean.Cat
@Configuration
public class MainConfig {
1
2
3

也可以将需要导入的组件集合定义在一个继承了ImportSelector的类中,并将此类通过@Import注解导入到容器中,如下:

public class MyImportSelector implements ImportSelector{

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
                // 通过全类名,导入需要的组件
        return new String[] {"com.atyintong.bean.Color"};
    }
}
1
2
3
4
5
6
7
8

【9】@FactoryBean:使用Spring提供的 FactoryBean (工厂Bean)。默认获取到的是工厂bean调用getObject()创建的对象,而要获取工厂Bean本身需要给id前面加一个 & 标识。如下:

/**
 * @ClassName:       CarFactoryBean
 * @Description:    实现 FactoryBean 接口,并在泛型中传入需要实例化的类
 * @author:          zzx
 * @date:            2019年1月13日        下午11:12:45
 */
public class CarFactoryBean implements FactoryBean<Car> {

    @Override
    public Car getObject() throws Exception {
        // 创建泛型中的对象,对象会添加到容器中
        return new Car();
    }

    @Override
    public Class<?> getObjectType() {
        // 对象的类型
        return Car.class;
    }

    @Override
    public boolean isSingleton() {
        // true 表示对象是单例,false 表示多实例
        return true;
    }
}
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

对上述理论的测试:

@Test
public void testFactory() {
    Object car0 = application.getBean("carFactoryBean");
    Object car1 = application.getBean("carFactoryBean");
    Object car2 = application.getBean("&carFactoryBean");
    //输入为 true,因为是单实例
    System.out.println(car0 == car1);
    //输出:com.atyintong.bean.Car@3d299e3
    System.out.println(car1);
    //输出:com.atyintong.condition.CarFactoryBean@55a561cf
    System.out.println(car2);
}
1
2
3
4
5
6
7
8
9
10
11
12

# 二、Bean 的声明周期

【1】bean指定初始化和销毁方法:通过指定initMethod属性指定初始化方法,destroyMethod属性指定销毁方法。其中initdestroy方法是Car对象中定义的方法。

@Bean(initMethod="init",destroyMethod="destory")
public Car car() {
    return new Car();
}
1
2
3
4

【2】类通过实现InitializingBeanDisposableBean接口

public class Cat implements InitializingBean,DisposableBean{

    @Override
    public void destroy() throws Exception {
        // 定义销毁逻辑
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 定义初始化逻辑
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

【3】@PostConstruct:对象创建并赋值之后调用,@PreDestory:容器移除对象之前。

public class Color {
    //对象创建并赋值之后调用
    @PostConstruct
    public void init() {

    }
    //容器移除对象之前
    @PreDestroy
    public void destory() {

    }
}
1
2
3
4
5
6
7
8
9
10
11
12

【4】后置处理器:BeanPostProcessor在类的init方法前执行postProcessBeforeInitialization方法中任务,在初始化init之后执行postProcessAfterInitialization方法。

@Component
public class MyBeanPostProcess implements BeanPostProcessor{

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //bean 表示当前类的全类名,beanName 表示容器中的 id
        /*  测试输入:构造函数。。。
            com.atyintong.bean.Car@1b083826---->car
            init 初始化方法,创建对象之前
            com.atyintong.bean.Car@1b083826---->car */
        System.out.println(bean+"---->"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(bean+"---->"+beanName);
        return bean;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 三、组件赋值

【1】@Value():进行属性赋值操作

public class Person {
    //使用@Value赋值;
        //1、基本数值
        //2、可以写SpEL; #{}
        //3、可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)

        @Value("${person.name}")
        private String name;
1
2
3
4
5
6
7
8

【2】@PropertySource():引入配置文件时使用,通过${key}获取配置内容

@PropertySource(value= {"classpath:/Persion.properties"})
public class MainConfig {
1
2

【3】@Autowired():自动注入,默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class) ,如果找到多个相同类型的组件,再将属性的名称作为组件id去容器中查找。但可以使用@Qualifier("xxx")指定需要装配的组件的 id,而不使用属性名。自动装备一定要将属性赋值号,如果没有在容器中找到此属性,就会报notfoundxxx错误,或者指定自动加载的required属性为false ,就不必须加载此类也不用报错。

@Service
public class BookService {
    @Qualifier("bookDao1")
    @Autowired(required=false)
    private BookDao bookDao;
1
2
3
4
5

当容器中存在多个同类对象时,我可以某个上添加@primary注解,当自动注入时,就会优先注入。

@Primary
@Bean("person01")
public Person person01() {
1
2
3

【4】@Resource:与@Autowired 一样实现自动装配功能,默认是按照组件名称进行装配。不支持@primary注解和required属性。

@Resource(name="bookDao")
private BookDao bookDao;
1
2

【5】@Inject:需要导入javax.inject包,和@Autowired功能一样,但其没有required属性。@AutowiredSpring 定义的,@Resource@Inject都是java规范。

@Inject
private BookDao bookDao;
1
2
(adsbygoogle = window.adsbygoogle || []).push({});