Spring-IOC

简单理解

spring就是一个容器,在这个容器中存放着一些公共的实例或者模板,当我们想使用是,直接从里面取就好了

介绍Spring

首先熟悉两个概念(这里只给出自己的简单理解)

1.IOC控制反转(控制反转指的事对象生成管理权)应用程序将对象的生成管理权交给了spring容器

2.DI依赖注入(从容器中获得我们想要的对象)

站在应用程序依赖的角度上:

应用程序依赖于IOC容器,并从中获取到所需要的资源(也就是对象)

站在注入的角度上:

容器注入了某个应用程序所依赖的资源,注入的是对象

通过示例理解

使用xml

  1. 首先定义接口和实现类

  2. 创建xml文件,在bean标签中有三个属性,1.id 2.name 3.全限定类名

  3. 使用test示例进行测试。

​ 案例一:不存在对象依赖

​ 1.首先创建ClassPathXmlApplicationContext容器

​ 2.利用applicationContext.getBean()从容器中取出组件,有三种方式,1>.通过id/name(这里的id和name都是自己起的),2>.通过全限定类名,3>.通过全限定类名和name

​ 案例二:存在对象依赖

​ 1.如在service类中增加dao类成员变量维护依赖关系,必须要在service中设置set方法

​ 2.在bean标签中增加标签,name值为自己取的,ref值为某个bean标签中的name

使用纯注解

首先使用注解的方式,要创建配置类等价替代xml文件

1.类上添加@Configuration注解,该类就成为一个配置类

方式一:在该类中增加@Bean注解

即@Bean注解所修的的方法即为一个Bean,Bean的name为方法名,也可以增加@Bean的value属性值作为name,全限定类名为返回值类型

3.解决了最基础的问题,现在来解决使用纯注解方式的依赖问题,一个方法中返回的是对象1,需要调用对象2作为该方法的参数,这就是@Bean注解中的依赖问题(有一个细节:我们需要自己创建对象)

4.解决了最基础的依赖问题,现在来解决如果Spring容器中有多个相同类型的对象怎么办?使用@Qualifier注解,通过在方法的参数前添加@Qualifier(“dataSource1”),dataSource1为该类中的其中一个方法

小结:通过使用纯注解+@Bean方式,我们使用了两个注解1.@Configuration创建配置类2.使用@Bean在容器中插入组件

现在又有新的问题,如果我们要将几十个类的对象作为Spring Bean住的到Spring容器中,那样配置类就会变得很繁琐,为了方便解耦和简化代码,我们可以

使用包扫描功能

​ 1.在配置类上增加ComponentScan注解,并直接指定包扫描路径@ComponentScan(“com.cskaoyan.demo1”)

​ 2.@Component注解,将包中的标记类对象注册为Spring Bean的注解。其中id默认为类名的首字母小写,也可以使用@Component中的value竖向来制定Spring Bean中的id

​ 3.除了@Component注解外还有@Service注解,@Repository注解,@Controller注解(@Component通用,@Service用于Service层,@Repository用于dao层,@Controller用于springMVC阶段)

使用包扫描功能,如何解决依赖注入问题?有三种解决方式:

构造器注入

​ 1.优先使用无参构造方法

​ 2.没有无参构造,则使用有参构造,如果这个类型的组件在容器中不止一个,则使用@Qualifier,常量值可以使用@Value

​ 3.如果有多个有参构造方法,则优先使用@Autowired注解的构造方法

方法注入

​ 默认这个方法不会自动执行:

​ 1.增加@Autowired,@Qualifier按需使用

成员变量注入(最常用的)

写在配置类中的属性和容器中

注入功能的注解使用这三组:

  1. @Autowired

  2. @Autowired + @Qualifier

  3. @Resource

    (Autowire默认按类型,resource默认先按名字,再按类型)

三:Spring单元测试

1.引入spring-test依赖

2.@Runwith和@ContextConfiguration注解

@RunWith(SpringJUnit4ClassRunner.class)  // 让测试类可以自动使用Spring容器
@ContextConfiguration(classes = ScanConfig.class) // 指定容器所使用的配置类(可以指定多个)

小结

1.自动依赖注入的前提是spring管理/创建对象

2.从创建对象的角度来讲,@bean注解和包扫描的区别,包扫描是spring创建,@bean是自己创建,如果一个已经存在的对象,则使用@bean

补充

1.单元测试

引入spring-test依赖

引入sp@Runwith和@ContextConfiguration注解,在单元测试类中可以使用注入功能的注解

2.FactoryBean

将目标对象注册为Spring Bean,我们得将返回目标对象(getObject方法)的FactoryBean子类对象注册为Spring Bean

Spring Bean

在spring Bean上添加注解,默认是Singleton单例,也可以添加Prototype(每次创建的都是新的对象)

生命周期

7个阶段

  1. Bean的实例化(有参构造方法、无参构造方法)
  2. 设置参数方法(方法注入、成员变量注入)@Autowired@Resource注解注入
  3. BeanNameAware、BeanFactoryAware、ApplicationContextAware
  4. BeanPostProcessor(Bean的后处理器,这个后指的是实例化之后,其实还是在放入到容器中之前)的postProcessBeforeInitialization(后面有初始化方法)(针对一个还不完整的bean处理
  5. 自定义的init方法(我们自己做开发的时候通常使用的方式)(除了使用@Autowired,@Resource之外的,一种实现依赖注入的方式@PostConstruct 是一个用于标注初始化方法的注解
  6. InitializingBean的afterPropertiesSet方法(通常是一些框架提供的类初始化的方式)(所有的依赖填充完了,让我们能够确保整改SpringBean的所有注入了依赖的属性)
  7. BeanPostProcessor的postProcessAfterInitialization(BeanPostProgress也能买到一个完整的Bean对象)(AOP核心)
/*

      对于Bean(容器中的组件),在容器中也会经历这样的一些阶段
        1.容器初始化的时候,组件做准备性工作 → 放入到容器中之前,会执行哪一些方法来准备实例**
        2.组件可以从容器中取出,提供服务,比如从容器中取出userService实例,调用其sayHello方法
        3.容器关闭,组件做销毁工作

      初始化阶段:
        1. Bean的实例化(有参构造方法、无参构造方法)
        2. 设置参数方法(方法注入、成员变量注入)
        3. BeanNameAware、BeanFactoryAware、ApplicationContextAware (Aware)
        4. BeanPostProcessor(Bean的后处理器,这个后指的是实例化之后,其实还是在放入到容器中之前)
           的postProcessBeforeInitialization(后面有初始化方法)针对一个还不完整的bean做处理
        5. 自定义的init方法(我们自己做开发的时候通常使用2的方式): 除了使用@Autowired,@Resource之外的,一种实现依赖注入的方式
        6. InitializingBean的afterPropertiesSet方法(通常是一些框架提供的类初始化的方式)所有的依赖都填充完了,
           让我们能够确保整改SpringBean的所有注入了依赖的属性
        7. BeanPostProcessor的postProcessAfterInitialization 让beanPostProcessor也能拿到一个完整的Bean对象

      销毁阶段:
      1. 自定义的destroy方法(通常是自定义的)
      2. DisposableBean的destroy方法(通常是框架提供的类采用这种方式)

      注意事项:
      1. @Bean 还是 包扫描方式,生命周期一致
      2. singleton scope的SpringBean 包含销毁阶段的声明周期,prototype scope的Spring Bean不包含
      3. BeanPostProcessor它不会处理其他的BeanPostProcessor


 */
// @Component
public class LifeCycelBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    // 定义构造方法
    public LifeCycelBean() {
        System.out.println(" 1. LifeCycelBean");
    }

    String parameter;

    @Autowired
    public void setParam(@Value("zs") String parameter) {
        System.out.println(" 2. Autowired setParam");
        this.parameter = parameter;
    }


    BeanFactory beanFactory;
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("3. setBeanFactory");
    }

    String beanName;
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("3. set setBeanName");
    }

    ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("3. setApplicationContext");
    }

    // 自定义初始化方法
    @PostConstruct
    public void init() {
        System.out.println("5. init");
    }



    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("6. afterPropertiesSet");
    }


    @PreDestroy
    public void preDestroy() {

        System.out.println("8. preDestroy");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("9. destroy");
    }
}

.在springbean中实现Aware…,然后定义对应的变量

2.定义getter、setter方法

3.在测试类中调用getter方法时,因为容器会初始化的时候自动调用setter方法,注入我们所需要的对象,如果结果能显示,则验证了这种猜想

PostProcessor会执行这个包下所有springBean,配置类和测试类都为springbean

@Component
public class CustomerBeanPostProcessor implements BeanPostProcessor {

    /*
         Sping容器会先调用这个方法
         1. 方法参数:
            1)bean就表示当前正在处理的对象(正在初始化的Spring Bean对象)
            2)beanName表示当前正在处理的对象名称(正在初始化的Spring Bean对象)
         2. 执行时机: 在每一个Spring Bean初始化阶段,都会调用该方法一次
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        System.out.println("4. postProcessBeforeInitialization: " + beanName);
        return bean;
    }



    /*
         Sping容器会后调用这个方法
         1. 方法参数:
            1)bean就表示当前正在处理的对象(正在初始化的Spring Bean对象)
            2)beanName表示当前正在处理的对象名称(正在初始化的Spring Bean对象)
         2. 执行时机: 在每一个Spring Bean初始化阶段,都会调用该方法一次
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("7. postProcessAfterInitialization: " + beanName);
        return bean;
    }
}

两个区别

使用@Bean方法的生命周期和使用包扫描的生命周期方式基本相同

1.区别:在使用@Bean方法,注册依赖阶段是自己创建的

2.scope区别:singleton scope的springBean包含销毁阶段的生命周期,prototype scope的springBean不包含销毁阶段的生命周期

区别2的原因:singleton scope 的 Spring Bean 由于由容器统一管理整个生命周期,所以有销毁阶段以进行资源清理;而 prototype scope 的 Spring Bean 更多依赖客户端代码使用情况,容器不主动管理其销毁阶段,因而默认没有销毁阶段相关的生命周期过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值