一、Spring基础及其组件的使用--Bean的注入以及Bean的生命周期

一、Spring体系结构

  1. Spring Core:Spring的核心,它是Spring框架最基础的部分,提供IOC和依赖注入特性。
  2. Spring Context:Spring上下文容器,它是BeanFactory功能加强的一个子接口。
  3. Spring Web:提供Web应用开发的支持。
  4. Spring MVC:针对Web应用中MVC思想的实现。
  5. Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。
  6. Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + HIbernate,Spring + Mybatis。
  7. Spring AOP:面向切面编程,提供了与AOP联盟兼容的编程实现。

本文主讲一些IOC容器基本组件的使用

IOC容器就是对bean进行管理:bean的注册、实例化和管理

二、Spring有哪些注入bean的方法

1、Spring通过bean.xml配置将bean实例化到IOC容器中:
<?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-4.1.xsd">
    <bean id="person" class="com.enjoy.cap1.Person">
        <property name="name" value="zhangSan"></property>
        <property name="age" value="19"></property>
    </bean>
</beans>
package com.enjoy.cap1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainTest1 {
    public static void main(String[] args) {
        //把beans.xml的类加载到容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //从容器中获取bean
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);
    }
}
2、通过注解实例化bean到IOC容器
  • @Configuration
    告诉Spring这是一个配置类
  • @Bean
    创建一个配置类(@Configuration),通过@Bean注解实例化
/**
 * 配置类 ---- 配置文件
 */
@Configuration
public class MainConfig {
    /**
     * 给容器中注册一个bean,类型为返回值的类型。bean的id为方法名,或者直接在注解中规定好bean的id
     */
    @Bean("aaaPerson")
    public Person person(){
        return new Person("liSi",20);
    }
}
  • @ComponentScan
    扫描规则:

① 指定扫描范围

@Configuration
@ComponentScan(value = "com.enjoy.cap2")
public class Cap2MainConfig {
    /**
     * 给容器中注册一个bean,类型为返回值的类型。bean的id为方法名,或者直接在注解中规定好bean的id
     */
    @Bean("aaaPerson")
    public Person person(){
        return new Person("liSi",20);
    }
}

② 扫描过滤器
Filter 分为一下几种:
在这里插入图片描述
使用includeFilters 方法,useDefaultFilters必须设置为false,如果为true,则将按照注解类型为Component进行引入bean。而Controller、Service和Repository都有@Component注解。
在这里插入图片描述在这里插入图片描述

@Configuration
//根据注解来判断注入哪些bean
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class Cap2MainConfig {
    /**
     * 给容器中注册一个bean,类型为返回值的类型。bean的id为方法名,或者直接在注解中规定好bean的id
     */
    @Bean("aaaPerson")
    public Person person(){
        return new Person("liSi",20);
    }
}
@Configuration
//根据注解来判断过滤掉哪些bean
@ComponentScan(value = "com.enjoy.cap2",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = true)
public class Cap2MainConfig {
    /**
     * 给容器中注册一个bean,类型为返回值的类型。bean的id为方法名,或者直接在注解中规定好bean的id
     */
    @Bean("aaaPerson")
    public Person person(){
        return new Person("lisi",20);
    }
}

③ 自定义过滤规则
自定义过滤规则的类:

public class CustomTypeFilter implements TypeFilter {
    private ClassMetadata classMetadata;

    /**
     * @param metadataReader:读取到当前正在扫描类的信息
     * @param metadataReaderFactory:可以获取到其他任何类信息
     */
    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);

        //当类包含er字符,则匹配成功,返回true
        if (className.contains("er")) {
            return true;
        }
        return false;
    }
}

引用的类:

//自定义拦截来注入bean
@Configuration
@ComponentScan(value = "com.enjoy.cap2", includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {CustomTypeFilter.class})
}, useDefaultFilters = false)
public class Cap2MainConfig {
    /**
     * 给容器中注册一个bean,类型为返回值的类型。bean的id为方法名,或者直接在注解中规定好bean的id
     */
    @Bean("aaaPerson")
    public Person person(){
        return new Person("lisi",20);
    }
}
  • @Scope
    IOC容器多实例和单实例:(给容器中注册一个bean,默认为单实例)
    ① 多实例:仅当bean被使用获取的时候才创建
    ② 单实例:创建IOC容器的时候,实例bean就被创建
    @Scope的使用:(多实例
@Configuration
public class Cap3MainConfig {
    //给容器中注册一个bean,类型为返回值类型,默认是单实例

    /*
     *  prototype:多实例,IOC容器启动的时候,IOC容器启动并不会调用方法创建对象,而是每次获取的时候才会调用方法创建对象
     *  singleton:单实例(默认),IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿同一个bean
     *  request:主要针对web应用,递交一次请求创建一个实例
     *  session:同一个session创建一个实例
     */
    @Scope("prototype")
    @Bean
    public Person person(){
        return new Person("ethan",18);
    }
}

测试结果:
在这里插入图片描述

  • @lazy 懒加载
    ① 什么是懒加载?
    懒加载主要是针对单实例bean,容器在启动的时候不创建对象,仅当第一次调用获取的时候才初始化bean。
    ② 懒加载的使用?
@Configuration
public class Cap4MainConfig {
    /**
     * 懒加载:主要针对单实例bean,单实例bean默认在容器启动的时候创建,
     * 使用@Lazy注解,容器启动时不创建对象,仅当第一次使用(获取)bean的时候才被初始化创建
     */
    @Lazy
    @Bean
    public Person person(){
        System.out.println("给容器中添加person......");
        return new Person("张三",20);
    }
}

在这里插入图片描述

  • @Conditional 条件注册bean

① 什么是条件注册bean?
规定一些条件,只有满足条件,才会注册某个bean实例。

②如何根据指定条件选择性的注册bean实例?

@Configuration
public class Cap5MainConfig {
    @Bean
    public Person person(){
        System.out.println("给容器中注入person实例bean。。。。。。");
        return new Person("person",18);
    }
    @Conditional(WinCondition.class)
    @Bean
    public Person zhangSan(){
        System.out.println("给容器中注入zhangSan实例bean。。。。。。");
        return new Person("person",18);
    }
    @Conditional(LinCondition.class)
    @Bean
    public Person liSi(){
        System.out.println("给容器中注入liSi实例bean。。。。。。");
        return new Person("person",18);
    }
}
public class WinCondition implements Condition {

    /**
     * @param conditionContext:判断条件可以使用的上下文(环境)
     * @param annotatedTypeMetadata:注解的信息
     * @return
     */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取IOC容器中正在使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取当前环境变量(包括我们操作系统是WIN还是LINUX)
        Environment environment = conditionContext.getEnvironment();
        String os_name = environment.getProperty("os.name");
        if (os_name.contains("Windows")) {
            return true;
        }
        return false;
    }
}
public class LinCondition implements Condition {

    /**
     * @param conditionContext:判断条件可以使用的上下文(环境)
     * @param annotatedTypeMetadata:注解的信息
     * @return
     */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取IOC容器中正在使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取当前环境变量(包括我们操作系统是WIN还是LINUX)
        Environment environment = conditionContext.getEnvironment();
        String os_name = environment.getProperty("os.name");
        if (os_name.contains("linux")) {
            return true;
        }
        return false;
    }
}

测试结果:
在这里插入图片描述

  • @Import 注册bean

① 手动添加组件到IOC容器

@Configuration
@Import(value = {Dog.class, Cat.class})
public class Cap6MainConfig {
    /**
     * @Import(要导入到容器中的组件):容器会自动注册这个组件,bean的id为全类名         
     */
    @Bean("person")
    public Person person(){
        return new Person("zhangsan",20);
    }
}

② 使用ImportSelector自定义返回组件
CustomImportSelector自定义引入选择类,实现ImportSelector接口:

public class CustomImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.enjoy.cap6.bean.Fish","com.enjoy.cap6.bean.Tiger"};
    }
}

使用案例:

@Configuration
@Import(value = {CustomImportSelector.class})
public class Cap6MainConfig {
    /**
     * @Import(要导入到容器中的组件):容器会自动注册这个组件,bean的id为全类名         
     */
    @Bean("person")
    public Person person(){
        return new Person("zhangsan",20);
    }
}

③ 使用ImportBeanDefinitionRegistrar返回自定义组件
自定义CustomImportBeanDefinitionRegistrar类,实现ImportBeanDefinitionRegistrar 接口:

public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * @param annotationMetadata:当前类的注解类
     * @param beanDefinitionRegistry:BeanDefinition注册类
     *            把所有需要添加到容器中的bean加入;
     */
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        boolean bean1 = beanDefinitionRegistry.containsBeanDefinition("com.enjoy.cap6.bean.Dog");
        boolean bean2 = beanDefinitionRegistry.containsBeanDefinition("com.enjoy.cap6.bean.Cat");
        //如果Dog和Cat同时存在于IOC容器中,那么就创建Pig类,注入到容器
        if (bean1 && bean2) {
            //通过RootBeanDefinition类将要注册的bean进行封装
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Pig.class);
            beanDefinitionRegistry.registerBeanDefinition("pig",rootBeanDefinition);
        }
    }
}

使用案例:

@Configuration
@Import(value = {CustomImportBeanDefinitionRegistrar.class})
public class Cap6MainConfig {
    /**
     * @Import(要导入到容器中的组件):容器会自动注册这个组件,bean的id为全类名         
     */
    @Bean("person")
    public Person person(){
        return new Person("zhangsan",20);
    }
}

④ FactoryBean接口实现
自定义CustomFactoryBean,实现FactoryBean接口,装配Monkey的类对象

public class CustomFactoryBean implements FactoryBean<Monkey> {
    public Monkey getObject() throws Exception {
        return new Monkey();
    }

    public Class<?> getObjectType() {
        return Monkey.class;
    }

    public boolean isSingleton() {
        return false;
    }
}

可在配置类中使用@Bean注入进来

	@Bean
    public CustomFactoryBean customFactoryBean(){
        return new CustomFactoryBean();
    }

注意点:app.getBean("&customFactoryBean") 获取到的bean是customFactoryBean对象,app.getBean(“customFactoryBean”) 获取到的bean是Monkey对象。

AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap6MainConfig.class);
        System.out.println("IOC容器创建完成......");

        Object bean1 = app.getBean("&customFactoryBean");//获取的bean是customFactoryBean
        Object bean2 = app.getBean("customFactoryBean");//获取的bean是Monkey
        System.out.println("bean的类型 = " + bean1.getClass());//打印结果是:bean的类型 = class com.enjoy.cap6.config.CustomFactoryBean
        System.out.println("bean的类型 = " + bean2.getClass());//打印结果是:bean的类型 = class com.enjoy.cap6.bean.Monkey

容器注册组件方式总结:

给容器中注册组件的方式:
① @Bean:【导入第三方的类或包的组件】,比如Person为第三方的类,需要在我们的IOC容器中使用
② 包扫描+组件的标注注解:(@ComponentScan:@Controller,@Service,@Reponsitory,@Component),一般是针对我们自己写的类,使用这个
③ @Import:[快速给容器导入一个组件] 注意:@Bean有点简单
a、@Import(要导入到容器中的组件):容器会自动注册这个组件,bean的id为全类名
b、ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
c、ImportBeanDefinitionRegisitrar:可以手动添加组件到IOC容器,所有Bean的注册可以使用BeanDifitionRegistry,写CustomImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
④ 使用Spring提供的FactoryBean(工厂bean)进行注册。

三、Bean的生命周期

对于单实例的bean,可以正常调用初始化和销毁方法,对于多实例的bean,容器只负责初始化,但不会管理bean,容器关闭的时候不会调用销毁方法。

  • Bean的生命周期指:Bean创建 --》初始化 --》销毁 的过程。
    ① 、我们可以自定义Bean初始化和销毁方法。容器在Bean进行到当前生命周期的时候,来调用自定义的初始化方法和销毁方法。
//定义一个类对象
public class Bike {
    public Bike (){
        System.out.println("Bike constructor ........ ");
    }
    public void init(){
        System.out.println("Bike ...... init ......");
    }
    public void destory(){
        System.out.println("Bike ...... destory ......");
    }
}

//配置类
@Configuration
public class Cap7MainConfigOfLifeCycle {
    @Bean(initMethod = "init",destroyMethod = "destory")
    public Bike bike(){
        return new Bike();
    }
}

//测试
@Test
public void test01(){
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap7MainConfigOfLifeCycle.class);
    System.out.println("IOC 容器创建完成。。。。。");
    app.close();
}

测试结果是:
在这里插入图片描述
②、实现InitializingBean接口的afterPropertiesSet()方法,当beanFactory创建好对象,切把bean所有属性设置好之后,会调用这个方法,相当于初始化方法。
实现DisposableBean的destory()方法,当bean销毁时,会把单实例bean进行销毁。

@Component
public class Train implements InitializingBean, DisposableBean {
    public Train() {
        System.out.println("Train......constructor............");
    }
    //当bean销毁时,调用此方法
    public void destroy() throws Exception {
        System.out.println("Train......destroy............");
    }
    //当bean属性赋值和初始化完成时调用
    public void afterPropertiesSet() throws Exception {
        System.out.println("Train......afterPropertiesSet............");
    }
}

//配置类
@ComponentScan("com.enjoy.cap7.bean") //扫描注入Train
@Configuration
public class Cap7MainConfigOfLifeCycle {
    @Scope("prototype")//多实例的bean,容器只负责初始化,但不会管理bean,容器关闭的时候不会调用销毁方法。
    @Bean(initMethod = "init",destroyMethod = "destory")
    public Bike bike(){
        return new Bike();
    }
}

//测试
@Test
public void test01(){
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap7MainConfigOfLifeCycle.class);
    System.out.println("IOC 容器创建完成。。。。。");
    app.close();
}

测试结果:
在这里插入图片描述
③ 使用JSR250规范定义(java规范)的两个注解实现 Bean生命周期–初始化与销毁
@PostConstruct:在Bean创建完成,且属于赋值完成后进行初始化,属于JDK规范的注解
@PreDestory:在Bean将被移除之前进行通知,在容器销毁之前进行清理工作

方法上使用@PostConstruct和@PreDestory注解来自定义实现bean初始化与销毁

@Component
public class Jeep {
    public Jeep() {
        System.out.println("Jeep ...... constructor ......");
    }
    @PostConstruct
    public void init(){
        System.out.println("Jeep ...... PostConstruct ......");
    }
    @PreDestroy
    public void destory(){
        System.out.println("Jeep ...... PreDestroy ......");
    }
}

//配置类
@Configuration
public class Cap7MainConfigOfLifeCycle {
    @Bean
    public Jeep jeep(){
        return new Jeep();
    }
}

//测试
@Test
public void test01(){
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap7MainConfigOfLifeCycle.class);
    System.out.println("IOC 容器创建完成。。。。。");
    app.close();
}

测试结果:
在这里插入图片描述
④使用 BeanPostProcessorsr 控制Bean的生命周期;
实现 BeanPostprocessors 的两个接口即可:
Ⅰ、postProcessBeforeInitialization()
Ⅱ、postprocessAfterInitialization()

//Bike类
public class Bike {
    public Bike (){
        System.out.println("Bike constructor ........ ");
    }
    public void init(){
        System.out.println("Bike ...... init ......");
    }
    public void destory(){
        System.out.println("Bike ...... destory ......");
    }
}

//实现BeanPostProcessor接口
@Component
public class CustomerBeanPostProcessor implements BeanPostProcessor {

    //返回一个对象(传过来的对象)
    //在初始化方法调用之前进行后置处理工作
    //什么时候调用它:init-method=init之前调用
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization......"+beanName+"......"+bean);
        return bean;
    }

	//返回一个对象(传过来的对象)
    //在初始化方法调用之前进行后置处理工作
    //什么时候调用它:init-method=init之后调用
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization......"+beanName+"......"+bean);
        return bean;
    }
}

//配置类
@ComponentScan("com.enjoy.cap7.bean")
@Configuration
public class Cap7MainConfigOfLifeCycle {
    //@Scope("prototype")
    @Bean(initMethod = "init",destroyMethod = "destory")
    public Bike bike(){
        return new Bike();
    }
}

//测试
@Test
public void test01(){
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap7MainConfigOfLifeCycle.class);
    System.out.println("IOC 容器创建完成。。。。。");
    app.close();
}

测试结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值