Spring IOC

1. IOC | 控制反转

削减程序间的耦合,例如用工厂模式来创建对象,但工厂模式要自己编写工厂类,Sping中完成了对此类的封装。

Spring的IOC容器是一个Map结构,Map<String, Object>

2. Spring只负责解耦

3. Sping配置

3.1 配置bean.xml

官网cv配置代码

<?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="accountService" class="com.alan.service.impl.AccountServiceImpl"></bean>
<bean id="accountDao" class="com.alan.dao.impl.AccountDaoImpl"></bean>

获取bean对象时可以通过两种方式指定类:
 

//获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取bean对象
IAccountService as = (IAccountService)ac.getBean("accountService");
//两种得到特定类型对象的方法,进行类型强转或者传入一个类型的字节码如下
IAccountDao adao = ac.getBean("accountDao", IAccountDao.class);

3.2 ApplicationContext接口

ApplicationContext是BeanFactory的子接口

 

 ApplicationContext接口的三个常用实现类

ClassPathXmlApplicationContext() //可以加载类路径下的配置文件,要求配置文件必须在类路径下,直接传入配置文件名
FileSystemXmlApplicationContext() //可以加载磁盘任意路径下的配置文件(必须有访问权限),需传入配置文件的绝对路径
AnnotationConfigApplicationContext() //读取注解创建容器

3.3 ApplicationContext和BeanFactory的区别

ApplicationContext:在构建核心容器时,创建对象采取的策略是立即加载,只要一读取完配置文件马上创建配置文件中的配置的对象。适用于单例对象。

可以根据对象的单例或多例采用立即加载还是延迟加载

BeanFactory:创建对象采用延迟加载策略,根据id获取对象时才会真正创建对象。适用于多例对象。

 4. 创建Bean对象细节

4.1 Bean创建的三种方式

<!--创建bean的三种方式-->
    <!--1. 使用默认构造函数,spring配置中使用bean标签,配以id和class且无其他属性和标签,类中必须有默认构造函数才可以创建成功-->
    <bean id="accountService" class="com.alan.service.impl.AccountServiceImpl"></bean>

    <!--2.使用普通工厂中的方法创建对象,并存入spring对象-->
    <bean id="instanceFactory" class="com.alan.factory.InstanceFactory"></bean>
    <!--使用创建的工厂类创建所需对象-->
    <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

    <!--3.使用工厂(或某个类)中的静态对象创建方法并存入spring容器-->
    <bean id="accountService" class="com.alan.factory.staticFactory" factory-method="getAccountService"></bean>

方法二对应以下工厂类文件:

public class InstanceFactory {
    public IAccountService getAccountService() {
        return new AccountServiceImpl();
    }
}
//由于重写了构造函数,InstanceFActory中没有默认构造函数

方法三对于以下工厂类文件:

public class staticFactory {
    public static IAccountService getAccountService() {
        return new AccountServiceImpl();
    }
}
//通过静态方法返回所需对象,因此需要factory-method来调用此静态方法

4.2 Bean对象的作用范围

Bean对象默认情况下是单例的,可通过bean标签的scope属性来调整bean的作用范围

取值:

singleton:单例的(default)

prototype:多例的

request:作用与web应用的请求范围

session:作用于web应用的会话范围

global-session:作用于集群环境的会话范围,但不是集群环境时,它就是session

拓展:session的作用范围

 4.3 bean对象的生命周期

单例:

创建:容器创建时对象创建,即读取配置文件时对象就被创建了

销毁:容器销毁时对象销毁

多例:

创建:使用对象时spring框架创建对象

销毁:当对象长时间不用,且没有别的对象引用时,由java的垃圾回收器回收

5. Spring的依赖注入

5.1 依赖注入(dependency Injection):

5.1.1 IOC降低耦合,依赖管理交给Spring维护,在当前类需要用到其他类的对象,由spring提供,只需在配置文件中说明,这种关系的维护称为依赖注入

常见于为类的属性进行初始化

5.1.2 能够注入的数据类型:

基本类型和String

其他bean类型(在配置文件或者注解配置过的bean)

复杂类型/集合类型

5.1.3 注入方式:

第一种:构造函数提供

第二种:使用set方法提供

第三种:使用注解提供

注:如果是经常变化的数据,不适合用注入的方式

5.2 构造函数注入:

方法:

使用标签<constructor-arg></constructor-arg>,置于bean标签内

适用:有含参构造函数的类

属性包括:

type: 用于指定要注入的数据类型,该数据类型是构造函数中某些参数的类型

index:指定要注入的数据给构造函数种指定索引位置的参数赋值,索引的位置从0开始

name:用于指定构造函数中指定名称中的参数赋值

================以上三个用于指定给构造函数中哪个参数赋值(一般直接用name)==================

value:要赋的值,都以字符串形式出现,用于给基本类型和String类型赋值,spring自动转类型

ref:引用其他bean类型,用其他bean类型数据的id赋值,要引用的对象需在bean中配置过

    <bean id="accountService" class="com.alan.service.impl.AccountServiceImpl" >
        <constructor-arg name="name" value="test"></constructor-arg>
        <constructor-arg name="age" value="12"></constructor-arg>
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>
    <bean id="now" class="java.util.Date"></bean>

弊端:有时候并不需要每个属性都赋值,但此方法不给每个方法赋值就无法创建对象。

5.3 set方法注入

方法:property标签,位于bean标签内部

适用:类无含参构造函数,且存在默认构造函数,且有属性对应的setter()方法

    <bean id="accountService2" class="com.alan.service.impl.AccountServiceImpl2">
        <property name="age" value="12"></property>
        <property name="name" value="Alan"></property>
        <property name="birthday" ref="now"></property>
    </bean>
    <bean id="now" class="java.util.Date"></bean>

优势:创建对象时没有明确限制,可以直接使用默认构造函数

弊端:如果某个成员必须有值,则获取对象有可能set方法无法保证一定注入

5.4 复杂数据类型注入

比如List,Map,Set,Properties,String[]

方法:<property></property>

    <bean id="accountService3" class="com.alan.service.impl.AccountServiceImpl3">
        <property name="myStr">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>

        <property name="myList">
            <list>
                <value>DDDD</value>
            </list>
        </property>

        <property name="myMap">
            <map>
                <entry key="123" value="456"></entry>
                <entry key="abc">
                    <value>efg</value>
                </entry>
            </map>
        </property>

        <property name="myProps">
            <props>
                <prop key="testc">ccc</prop>
                <prop key="testb">bbb</prop>
            </props>
        </property>
    </bean>

注:用于给List结构集合注入的标签:

<list></list>

<array></array>

<set></set>

用于给Map结构集合注入的标签:

<map></map>

<props></props>

以上,结构相同,标签可以互换。

5.5 注解注入

@Component

@Controller  //一般用在表现层

@Service  //一般用在业务层

@Repository  //一般用在持久层

以上作用和属性完全一致,分别用于三层框架,如果不属于任何一层,一般用@Component

5.5.1 @Component

/**
 * 账户的业务层实现类
 * <bean id="accountService" class="com.alan.service.impl.AccountServiceImpl"
 *      scope="" init-method="" destory-method="">
 *      <property name="" value="" | ref=""></property>
 *</bean>
 * Component用于把当前类对象存入spring容器中,属性value:用于指定bean的id,不写时,
 * 默认值是当前类名且首字母改小写
 */
@Component
public class AccountServiceImpl implements IAccountService {
    private IAccountDao accountDao;

    public void saveAccount() {
        accountDao.saveAccount();
    }
}

@Component也可自己指定要得到对象的id:

@Component(value = "accountService")

bean.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是在一个名称为context名称空间和约束中-->
    <context:component-scan base-package="com.alan"></context:component-scan>
    <!--会扫描所有类上和接口上的注解-->
</beans>

5.5.2 注解注入类属性

@Autowired

 /**  Autowired:
 *      自动按照类型注入,只要容器中有唯一(必须是唯一)的
 *   一个bean对象类型和要注入的变量类型匹配,就可以注入成功。
 *      如果有多个类型匹配,要先根据类型圈定匹配对象,
 *   会使用变量名称作为id在map中的bean中进行选择
 *      位置:变量上,方法上
 *      优势:使用注解注入时,set方法不是必要的
 */
@Service(value = "accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao accountDao2;

    public void saveAccount() {
        accountDao2.saveAccount();
    }
}

注:当IOC容器中有多个匹配的bean(同一接口的不同实现类)时,会根据属性名和实现类名一致的原则进行匹配,如以下情况中就会将AccountDaoImpl2类型的对象注入

 

IOC容器中的bean

 5.5.2.1 @Qualifier | @Resource

@Qualifier 解决了@Autowired在有多个实现相同接口的类的bean时不能指定注入对象的问题

但要和@Autowired配合使用

 /**     Qualifier:
 *      在按照类型注入的基础上再按照名称注入,在给类成员注入时不能单独使用,但给方法参数注入时可以
 *      属性:
 *          value:指定注入bean的id
 *      注:必须和@Autowired配合使用
 */
@Service(value = "accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    @Qualifier("accountDao1")
    private IAccountDao accountDao;

    public void saveAccount() {
        accountDao.saveAccount();
    }
}

@Resource

可以单独使用,属性为name=""

 /**  Resource:
 *      直接按照bean的id注入,可以独立使用,属性为name,指定bean的id
 */
@Service(value = "accountService")
public class AccountServiceImpl implements IAccountService {
    @Resource(name="accountDao1")
    private IAccountDao accountDao2;

    public void saveAccount() {
        accountDao2.saveAccount();
    }
}

小结:@Autowired @Qualifier @Resource都只能注入其他bean类型的数据,基本类型和String类型无法用上述注解实现,集合类型的注入只能通过XML实现。

5.5.3 @Scope | @PreDestroy | @PostConstruct

 /**Scope
 *      指定单例或多例
 *      属性 value,取值为singleton或prototype
 *  PreDestroy
 *      用于指定销毁方法
 *  PostConstruct
 *      用于指定初始化方法
 */
@Service(value = "accountService")
@Scope(value = "singleton")
public class AccountServiceImpl implements IAccountService {
    @Resource(name="accountDao1")
    private IAccountDao accountDao2;
    @PostConstruct
    public void init() {
        System.out.println("init");
    }
    @PreDestroy
    public void destroy() {
        System.out.println("destroy");
    }

    public void saveAccount() {
        accountDao2.saveAccount();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值