Spring-IOC 控制反转

什么是框架?

  所谓的框架就是程序的架子,在程序的架子中,搭建起程序的基本骨架,针对程序的通用问题给出了方便的解决方案,为开发人员能够基于框架快速地开发具体的应用程序程序提供帮助。
  在java常见的框架有SSH框架(Struts2、Spring、Hibernate)和SSM框架(Spring、SpringMVC、MyBatis),在SSH框架中由于Struts2框架爆发过很多高危漏洞,使用起来有很大的安全隐患,所以随着SSM框架的流行SSH也随之过时。

Spring框架概述

  Spring是一个Service层的框架,可以整合许多其他框架进行工作,Spring的主要技术是IOC(DI)AOP
   IOC(DI)-控制反转(依赖注入)
   AOP-面向切面编程
  如果想要下载Spring框架所需jar包,则登录https://spring.io进行下载即可。
注:为了帮助广大网友方便的学习SSM框架,可以发送邮箱1159768380@qq.com,这里笔者可以向大家提供了SSM相关的所有jar包。

配置Spring的约束

  Spring本身是基于xml配置来工作的,在使用Spring的过程中不可避免的要编写大量的xml配置,所谓的xml的约束其实是一种限定xml文件写法的技术,主要分为两种:
DTD:通常文件后最为 .dtd
Schema:通常文件的后缀为 .xsd
  Spring提供了Schema格式的约束,来限定Spring配置文件的写法,由于这个过程比较麻烦这里就不详细的介绍了。开发人员通常会将约束文件交给开发工具来管理,开发工具可以通过解析约束文件了解xml文件的写法,并在需要时为开发者提供标签支持。

Spring IOC

  所谓的IOC称之为控制反转,简单来说就是将对象创建的权力及对象的生命周期的管理过程交给Spring框架来处理,从此在开发过程中不在需要关注对象的创建和生命周期的管理,这个由Spring框架管理对象创建和生命周期的机制称之为控制反转。下面我们可以通过一个小小的案例体会一下控制反转的使用。
1.创建一个java工程导入spring框架相关的jar包
在这里插入图片描述
2.创建Spring配置文件
  Spring采用xml文件作为配置文件,xml文件名任意,但通常取名为applicationContext.xml。通常将该文件放置在类加载的目录(src目录)下。
在这里插入图片描述
3.创建bean类,并在spring中配置交由spring来管理。这里在src目录下创建了cn.springstudy.domain包下Person类。
xml文件的配置如下

<?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.xsd">
       
    <bean id="person" class="cn.springstudy.domain.Person"></bean>
    
</beans>

4.在程序中通过Spring容器获取对象并使用

public class Test01 {
    @Test
    public void test01(){
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person = (Person) context.getBean("person");
        person.study();
    }
}

打印结果为:
在这里插入图片描述

IOC的实现原理

  在初始化一个Spring容器的时候,Spring会去解析指定的xml文件(applicationContext.xml)。当解析到<bean>时,会根据该标签中class属性指定全路径名,通过反射创建该类的对象,并将该对象存入Map中管理其中键就是该标签的id值,值就是该对象。
当通过getBean方法从容器中获取对象时,其实就是根据传入的条件在内置的Map中寻找是否有匹配的键值,如果有则将该键值对保存的对象返回,如果没有匹配是则报出异常。由此可以推断出:
1.默认情况下,多次获取同一个id的bean,得到的是同一个对象。
2.即使是同一个类,如果配置过多的<bean>标签且具有不同的id,每个id都会在内置的Map中有一个键值对,其中的值是这个类创建的不同的对象。
3.同一个<beans>标签下不允许配置过多个相同id的<bean>标签,如果启动则爆出异常。

IOC获取对象的方式

通过context.getBean()方法获取bean时,可以通过如下两种方法获取:
  1.传入id值
  2.传入class类型
通过class方法获取bean时,如果同一个类配置了过多的bean,则在获取时因为无法确定到底要获取哪一个bean会抛出异常。而id是唯一的,不存在这样的问题,所以在这里建议大家尽量使用id获取bean。SpringIOC在通过class获取bean时,如果找不到该类型的bean还回去检查是否存在该类型的子孙类型的bean,如果有则返回,如果找不到或者找到多个则会抛出异常。这个符合java变成思想中的多态。

Spring创建对象的方式

1.通过类的无参构造方法创建对象
  在刚才的入门案例中使用的就是这种方法。当用最普通的方法配置一个<bean>时,默认采用的是无参构造创建对象。在Spring初始化容器时通过<bean>上的配置的class属性反射得到字节码对象,通过newInstance()创建对象。

Class c=Class.forName("类的全路径名称");
Object obj=c.newInstance();

  这种方式下Spring创建对象,要求类必须有无参的构造,否则无法通过反射创建对象,会抛出异常。
在这里插入图片描述
2.通过静态工厂创建对象
  很多的时候,我们面对的类是无法通过无参构造方法创建的,例如该类没有无参构造,或者是一种抽象类等等。此时无法要求Spring通过无参构造创建对象,此时可以使用静态工厂的方式创建对象。
a.创建静态工厂

/**
 * 静态工厂
 *      构造器私有化,保证工厂只有一个
 *      提供静态的创建目标对象的方法,使用者直接通过类名调用此静态方法获取对象
 */
public class PersonStaticFactory {
    private PersonStaticFactory() {
    }

    public static Person getInstance(){
        return new Person("张三");
    }
}

b.在xml文件中配置<bean>标签

<?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.xsd">
     
    <!--静态工厂创建bean-->
     <bean id="person" class="cn.springstudy.factory.PersonStaticFactory" factory-method="getInstance"/>

</beans>

c.测试同上
3.通过实例工厂创建对象
  实例工厂也可以解决类是无法通过无参构造创建的问题,解决思路与静态工厂类似,只不过实例工厂提供的方法不是静态的。spring需要先创建实例工厂的对象,在调用实例工厂对象上指定的普通方法来创建对象。所以实例工厂也需要配置到spring中管理。
a.创建实例工厂

/**
 * Person类的实例工厂
 *      构造器不可以私有化,提供共有无参构造器
 *      提供普通方法来创建目标对象
 */
public class PersonInstanceFactory {
    public Person getInstance(){
        return new Person("ls");
    }
}

b.在xml文件中配置<bean>标签

<?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.xsd">

     <!--实例工厂创建bean-->
     <bean id="personInstanceFactory" class="cn.springstudy.factory.PersonInstanceFactory"></bean>
     <bean id="person" factory-bean="personInstanceFactory" factory-method="getInstance"></bean>
    
</beans>

c.测试同上
4.Spring工厂创建对象
a.Spring内置了工厂接口,也可以通过实现这个接口来开发Spring工厂,通过这个工厂创建对象。

/**
 * Spring工厂
 *  必须实现FactoryBean的接口,并通过泛型指定要创建的对象类型
 */
public class PersonSpringFactory implements FactoryBean<Person> {
    /**
     * 获取目标对象
     */
    @Override
    public Person getObject() throws Exception {
        return new Person("ww");
    }

    /**
     * 获取目标对象类型
     */
    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }

    /**
     * 是否以单例模式创建对象
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

b.在xml文件中配置<bean>标签

<?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.xsd">

    <!--Spring工厂创建bean-->
    <bean id="person" class="cn.springstudy.factory.PersonSpringFactory"></bean>
    
</beans>

c.测试同上

单例和多例

  Spring容器管理的bean在默认情况下是单例的,也即,一个bean只会创建一个对象,存在内置的Map中,之后无论获取多少次该bean,都返回的是同一个对象。Spring默认采用单例方式,减少了对象的创建,从而减少了内存的消耗。但是实际开发中存在多例的需求,Spring也提供了选项可以将bean设置为多例模式。

<?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.xsd">
    <!--
        单例多例
            singleton
                单例模式
                容器初始化时创建,存入容器内部map
                之后无论获取多少次得到的都是同一个对象
            prototype
                多例模式
                容器初始化时不创建
                每次用到重新创建一个新的对象,此对象不会存入容器内map管理,其生命周期和普通的对象一样
                每次获取拿到的都是一个全新的对象
    -->
    <bean id="person" class="cn.springstudy.domain.Person" scope="prototype"></bean>
</beans>

bean在单例模式下的生命周期
  bean在单例模式下,Spring容器启动时解析xml文件发现bean标签后,直接创建bean的对象存入内部map中保存,此后无论调用多少次getBean()获取该bean都是从map中获取对象返回,一直都是同一个对象。此对象一直被Spring容器持有,直到容器退出时,随着容器的退出对象被销毁。

bean在多例模式下的生命周期
  bean在多例模式,Spring容器启动时解析xml发现该bean标签后,只是将该bean进行管理,并不会创建对象,此后每次使用getBean()获取该bean时,Spring都取决于使用该对象的用户自己什么时候销毁该对象。

懒加载机制

  Spring默认会在容器初始化的时候,解析xml文件,并将单例的bean创建保存到map中,这样的机制在bean比较少的时候问题不大,但一旦bean非常多时,Spring需要在启动的过程中花费大量的时间创建bean花费大量的内存空间存储bean,但这些bean可能很久都用不上,这种在启动时在时间和空间上浪费显然十分不值得。所以Spring提供了懒加载机制。所谓的懒加载机制就是可以规定指定的bean不在启动时立即创建,而是在后续第一次用到的时候才能创建,从而减轻在启动过程中对时间和内存的消耗。
xml文件配置:
1.为指定bean配置懒加载

<?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.xsd">
    
    <bean id="stu" class="cn.springstudy.domain.Person" lazy-init="true"></bean>

</beans>

2.为全局配置懒加载

<?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.xsd"
       default-lazy-init="true"
>

    <bean id="stu" class="cn.springstudy.domain.Person" ></bean>

</beans>

注:如果同时设定全局和指定bean的懒加载,且配置不同,则对与该bean的局部配置覆盖全局配置。

配置初始化和销毁方法

  在Spring中如果某个bean在初始化之后或者销毁之前要做一些额外的操作可以为该bean配置初始化和销毁方法,在这些方法中完成功能
a.创建方法类:

public class InitAndDestroy {
    public void init(){
        System.out.println("初始化方法");
    }
    public void destroy(){
        System.out.println("销毁方法");
    }
}

b.xml配置:

<?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.xsd"
       default-lazy-init="true"
>

    <bean id="initAndDestroy" class="cn.springstudy.domain.InitAndDestroy"
          init-method="init" destroy-method="destroy"/>

</beans>

Spring中关键字方法的执行顺序
  在Spring创建bean对象时,先创建对象(通过无参构造或者工厂),之后立即调用init()方法来执行初始化操作,之后此bean就可以拿来调用其他的普通方法,而在对象销毁之前。Spring容器最后会调用destroy()方法执行销毁操作。

由于Spring框架的内容较多,本文不能完全介绍完,后续还会更新。

Spring-IOCSpring框架的核心部分之一,它是一种设计模式,全称为Inversion of Control(控制反转)。它通过将对象的创建、依赖关系的管理和对象的生命周期交给Spring容器来实现,从而降低了组件之间的耦合度,提高了代码的可重用性和可维护性。Spring-IOC的实现主要依靠Spring容器,Spring容器是Spring框架的核心,它负责创建、管理和装配Bean对象,其中Bean是Spring框架中最基本的组件。 Spring-IOC的实现主要有两种方式:BeanFactory和ApplicationContext。其中,BeanFactory是Spring-IOC的基本实现,而ApplicationContext是BeanFactory的子接口,提供了更多高级特性。ApplicationContext是Spring框架中最常用的IOC容器,它除了提供BeanFactory的所有功能外,还提供了更多的企业级特性,例如AOP、事务管理、国际化、事件传播等。 下面是一个简单的Spring-IOC的例子,假设我们有一个UserService接口和一个UserServiceImpl实现类,我们可以通过Spring-IOC容器来创建和管理UserServiceImpl对象: 1.定义UserService接口和UserServiceImpl实现类 ```java public interface UserService { void addUser(User user); } @Service public class UserServiceImpl implements UserService { @Override public void addUser(User user) { // 添加用户的具体实现 } } ``` 2.在Spring配置文件中配置UserService实例 ```xml <bean id="userService" class="com.example.service.UserServiceImpl"/> ``` 3.在代码中获取UserService实例并使用 ```java ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = context.getBean("userService", UserService.class); User user = new User(); userService.addUser(user); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值