Spring简介 (1) IOC-控制反转

1. Spring是什么

  • Spring是一个针对bean的生命周期进行管理的轻量级容器框架,它同时也是SpringMVC,SpringBoot,SpringCloud等Spring开源框架的基石,Spring提出了IOC,AOP,DI等重要的概念(功能),本文主要介绍IOC(Inversion of Control)控制反转的概念

2.IOC基本介绍

在面向对象编程时我们通常通过new关键字来初始化一个bean对象并进行使用,而在Spring中我们将bean的信息和bean之间的依赖关系通过XML文件/注解配置好后,交给Spring来帮助我们初始化bean对象,并放入容器中进行统一管理。这样程序员可以更加关注如何使用对象完成业务逻辑。

这就引出了IOC控制反转的概念,程序员不再主动new一个对象,而是将控制权交给Spring容器,让它帮我们进行bean的配置,DI(Dependency Injection)是IOC的另一种叫法,就是通过配置bean对象之间的依赖关系,初始化bean对象注入到spring容器中

1. Spring容器的结构剖析

我们先通过XML文件配置的方式配置一个bean对象

<bean id="person01" class="ioc.beans.Person">
        <property name="name" value="tom"/>
        <property name="age" value="19"/>
        <property name="gender" value="male"/>
</bean>

再通过创建容器得到配置到容器中的bean对象

@Test
public void getBean() {
	//创建一个Spring容器
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    //获取容器中的bean对象
    Person person01 = ioc.getBean("person01", Person.class);
    System.out.println(person01);
}

我们通过Debug来看看Spring的容器结构 spring容器中的一个重要字段beanFactory维护了一个beanDefinitionMap字段 他的类型为ConcurrentHashMap,key作为bean的唯一标识id,value的类型为GenericBeanDefinition里面,存储了bean的信息(类型,懒加载,属性值等)
在这里插入图片描述
beanFactory中还有一个重要字段singletonObjects(单例池),在我们通过xml文件配置bean时默认为singleton(单例), spring就会把单例对象放入单例池中,这样我们通过getBean方法就可以获取到对应的bean
在这里插入图片描述

2. 获取Bean对象的三种方式

  • 通过类型获取
    该方式要求的前提是容器中只存在与该类型唯一匹配的bean对象,否则就会报错
 Person person01 = ioc.getBean(Person.class);
  • 通过id获取
    该方式可以通过配置bean时设置的唯一标识id获取对应对象返回类型是Object(需要强转),如果没有设置则默认为 ioc.beans.Person#0 全类名#0(1,2…)
Object person01 = ioc.getBean("person01");
  • 通过id和类型获取
Object person01 = ioc.getBean("person01", Person.class);

和第二种方式相同但是直接返回的是对应的类型不需要强转

3.基于XML文件配置Bean对象

spring底层在都是通过反射的方式创建一个bean对象,所以要确保bean类有无参构造器,和setter/构造方法

  1. 通过setter方法设置属性

spring通过反射调用无参构造器后 调用setter方法初始化对象的属性

<bean id="person01" class="ioc.beans.Person">
        <property name="name" value="tom"/>
        <property name="age" value="19"/>
        <property name="gender" value="male"/>
</bean>
  1. 通过构造器设置属性

spring调用对应的有参构造器初始化属性

<bean id="person02" class="ioc.beans.Person">
        <constructor-arg index="0" value="jack"/>
        <constructor-arg index="1" value="19"/>
        <constructor-arg index="2" value="male"/>
</bean>
  1. 通过p名称空间(setter方法)设置属性
<bean id="person03" class="ioc.beans.Person"
    p:name="mary" p:age="3" p:gender="female" />
  1. 注入其他bean对象

将school中的dept引用指向id为dept的对象

<bean id="dept" class="ioc.beans.Dept"/>

<bean id="school" class="ioc.beans.School">
     <property name="dept" ref="dept"/>
</bean>
  1. 注入内部bean对象
<bean id="school" class="ioc.beans.School">
        <property name="dept">
            <bean class="ioc.beans.Dept">
                <property name="id" value="1"/>
            </bean>
        </property>
</bean>
  1. 注入集合/数组
<bean id="master" class="com.syf.spring.bean.Master">
        <property name="name" value="master"/>
        <property name="monsterName">
            <array>
                <value>m1</value>
                <value>m2</value>
            </array>
        </property>
      
        <property name="monsterList">
            <list>
                <ref bean="monster01"/>
                <ref bean="monster02"/>
            </list>
        </property>
        <property name="monsterMap">
            <map>
                <entry key="m1" value-ref="monster01"/>
                <entry key="m2" value-ref="monster02"/>
                <entry key="m3">
                    <bean class="com.syf.spring.bean.Monster">
                        <property name="name" value="m3"/>
                        <property name="age" value="3"/>
                        <property name="skill" value="s3"/>
                    </bean>
                </entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="m1">s1</prop>
                <prop key="m2">s2</prop>
            </props>
        </property>
</bean>
  1. 通过util名称空间创建list

这种方式可以实现对List属性的重用,即可以有多个bean对象引用该List

<util:list id="monsterList">
        <ref bean="monster01"/>
        <ref bean="monster02"/>
</util:list>

<!--引用util list-->
<property name="monsterList" ref="monsterList"/>
  1. 级联属性赋值

注入dept时并没有给它的属性初始化,而是在emp中初始化

<!--级联属性赋值-->
<bean id="dept" class="com.syf.spring.bean.Dept"/>
    <bean class="com.syf.spring.bean.Emp" id="emp">
        <property name="name" value="emp"/>
        <property name="dept" ref="dept"/>
        <property name="dept.name" value="no1"/>
</bean>
  1. bean信息的重用

通过设置parent重用person07的信息相当于一种继承关系

<bean id="person07" class="ioc.beans.Person">
        <property name="name" value="tom"/>
        <property name="age" value="19"/>
        <property name="gender" value="male"/>
    </bean>
<bean id="person08" class="ioc.beans.Person" parent="person07"/>
  1. bean的自动装配

根据byType实现自动装配
要求被装配的属性类型 在容器中唯一匹配与之相同类型的bean

<bean id="dao" class="ioc.beans.Dao"/>
<bean id="service" class="ioc.beans.Service" autowire="byType"/>

根据byName实现自动装配
根据setter方法 setXxx后面的 xxx 去匹配容器中的bean的id,匹配上就会装配

<bean id="dao" class="ioc.beans.Dao"/>
<bean id="service" class="ioc.beans.Service" autowire="byName"/>

4.通过bean工厂获取对象

1. 静态工厂获取

public class StaticFactory {

    private static ConcurrentHashMap<String, Person> map;

    static {
        map = new ConcurrentHashMap<>();
        map.put("person01", new Person("mike", 19, "male"));
        map.put("person02", new Person("jack", 19, "male"));
    }
    
    public static Person getBean(String id) {
        return map.get(id);
    } 
}

<bean id="person04" class="ioc.factory.StaticFactory" factory-method="getBean">
        <constructor-arg index="0" value="person01"/>
</bean>

2.实例工厂获取

public class InstanceFactory {

    private ConcurrentHashMap<String, Person> map;

    {
        map = new ConcurrentHashMap<>();
        map.put("person01", new Person("mike", 19, "male"));
        map.put("person02", new Person("jack", 19, "male"));
    }

    public Person getBean(String id) {
        return map.get(id);
    }
}

<bean class="ioc.factory.InstanceFactory" id="factory"/>
    <bean id="person05"  factory-bean="factory" factory-method="getBean">
        <constructor-arg index="0" value="person01"/>
</bean>

3.实现FactoryBean接口获取

public class MyFactoryBean implements FactoryBean<Person> {
	
    private String key;
    private Map<String, Person> map;

    {
        map = new ConcurrentHashMap();
        map.put("person01", new Person("mike", 19, "male"));
        map.put("person02", new Person("mary", 19, "female"));
    }

    public void setKey(String key) {
        this.key = key;
    }

    @Override
    public Person getObject() throws Exception {
        return map.get(key);
    }

    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

<bean id="person06" class="ioc.factory.MyFactoryBean">
        <property name="key" value="person02"/>
</bean>

5.基于注解配置bean

一.简介
此方法主要是配置项目开发中的组件 Controller Service Dao
1.@Component 表示当前注解标识的是一个组件
2.@Controller 表示当前注解标识的是一个控制器,通常用于 Servlet
3.@Service 表示当前注解标识的是一个处理业务逻辑的类,通常用于 Service 类
4.@Repository 表示当前注解标识的是一个持久化层的类,通常用于 Dao 类

  1. 这些注解配置的都是单例bean对象,需要在XML文件中配置要自动扫描的包 还可以使用 * 通配符来指定比如
    ioc.*表示扫描ioc下面所有的文件
<context:component-scan base-package="ioc.component"/>
  1. 表示只扫描符合pattern的类
<context:component-scan base-package="ioc.component" resource-pattern="User*.class"/>
  1. 排除(不扫描)某些注解
<context:component-scan base-package="ioc.component" resource-pattern="User*.class">
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>

4.指定扫描某些注解
use-default-filters=“false” 指不再使用默认的过滤机制(全部扫描)

<context:component-scan base-package="ioc.component" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

二.注解的自动装配

两种注解都可以实现自动装配 @AutoWired @Resource

1.@AutoWired自动装配机制

  • 在spring容器中查找待装配组件的类型,如果有唯一匹配则自动装配
  • 如果有多个匹配,则按照待装配的组件的属性名作为id 进行查找匹配,找到就自动装配,找不到就抛异常
  1. @Resource自动装配机制

@Resource有两个属性name 和 type,分别是根据byName和byType策略进行装配

  • 如果不指定name或者type则默认根据byName策略进行装配,即根据属性名作为id在容器中进行匹配如果没有匹配上,则根据byType策略装配
  • 如果指定name,则根据name作为id查找容器中的bean,如果设置的id在容器中不存在,则编译会报错

三.泛型依赖注入

为了更好的管理有继承和相互依赖的 bean 的自动装配,spring 还提供基于泛型依赖的 注入机制

public abstract class BaseDao<T> {
   
    public abstract void save();

}

@Repository
public class MemberDao extends BaseDao<MemberDao>{
    @Override
    public void save() {
        System.out.println("memberDao save() method");
    }
}

public abstract class BaseService<T> {

    @Resource
    private BaseDao<T> baseDao;

    public void save() {
        baseDao.save();
    }
}

@Service
public class MemberService extends BaseService<Member>{
}

6.Bean对象的生命周期

在spring容器中注入的bean默认为单例(singleton), 即配置完bean之后,容器之后创建一个bean对象。默认为非懒加载(lazy-init),即在启动容器时就创建了bean对象

如果我们希望每次getBean都得到一个新的bean对象可以声明scope=“prototype”进行配置

bean对象配置初始化方法和销毁方法
init-method=“init” destroy-method=“destroy”

<bean id="person01" class="ioc.beans.Person"
          init-method="init" destroy-method="destroy">
        <property name="name" value="tom"/>
        <property name="age" value="19"/>
        <property name="gender" value="male"/>
</bean>

bean对象的生命周期

  1. 创建对象调用无参构造器
  2. 调用setter方法
  3. 后置处理器
  4. 初始化方法
  5. 后置处理器
  6. 容器关闭 销毁方法
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值