一、引入xml和注解

1.在Spring中的两个个重要概念一个是IoC,一个是bean;bean是Spring IoC实例化、管理、装配的对象,那么Spring IoC如何管理bean呢?答案是:基于xml管理bean和基于注解管理bean。

 二、Spring管理bean的第一种方式-xml

1.Spring框架搭建过程

1. 配置pom.xml文件

2. 创建pojo实体类

3. 创建配置文件applicationContext.xml

<bean id="hellospring" class="com.gz.pojo.HelloWorld"></bean>

    * bean:配置一个bean对象,将对象交给IOC容器管理

    * Spring提供的对象默认是单例的,一个bean提供一个对象

    * 包含的属性:

        * id:bean的唯一标识,不能重复

        * class:设置bean对象所对应的类型(只能为类,不能为接口)

4. 进行测试

    1. 获取IOC容器

    2. 获取IOC容器中的bean对象

@Test
public void testHelloWorld(){
//1.获取IOC容器:使用ApplicationContext的子类:ClassPathXmlApplicationContext
ClassPathXmlApplicationContext ioc = new 
          ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取IOC容器中的bean对象:使用getBean()方法
HelloWorld helloworld = (HelloWorld) ioc.getBean("hellospring");
//调用该类中的方法
helloworld.sayHello();
}

2.xml配置文件

1.在Spring框架的搭建过程中,一个重点是要创建配置文件applicationContext.xml,在applicationContext.xml中创建bean对象,设置bean对象的id和class为后续获取bean对象做好准备。这就是xml文件的作用之一。

2.xml配置文件的其他作用:

        进行依赖注入

        进行自动装配

3.xml进行依赖注入

依赖注入:为当前的类的属性赋值;有两种方法进行依赖注入:

* setter注入

    * 标签:property:通过成员变量的set方法进行封装

        * name:设置需要赋值的属性名(和set方法有关)

        * value:设置为属性所赋的值

<bean id="studentOne" class="com.gz.spring.pojo.Student">
        <property name="id" value="1001"></property>
        <property name="name" value="李四"></property>
        <property name="age" value="11"></property>
        <property name="gender" value="1"></property>
    </bean>

* 构造器注入

    * 标签:constructor-arg

        * 注意:value值应与有参构造器相对应;

        * 若存在两个相同参数的构造器时,可以通过属性来匹配指定的有参构造器

<bean id="studentFour" class="com.gz.spring.pojo.Student">
        <constructor-arg value="1004"></constructor-arg>
        <constructor-arg value="赵四"/>
        <constructor-arg value="14"></constructor-arg>
        <constructor-arg value="男"></constructor-arg>
    </bean>

* 特殊值处理

    1. 字面量赋值(字面量:包装类/String)

        * value中的值就是给字面量赋的值

    2. null赋值:不能用value=null赋值,而是在当前property里面设置null标签

<bean id="studentFive"  class="com.gz.spring.pojo.Student">
        <property name="id">
            <null />
        </property>
    </bean>

* 存在问题: < 在xml文档中用来定义标签的开始,不能随便使用

   3.  第一种方法:xml赋值

        * 使用xml实体代替:

            * &lt; 表示 <    &gt; 表示 >

<bean id="studentSix" class="com.gz.spring.pojo.Student">
    <property name="name" value="a < b"></property>
</bean>

        第二种方法:CDATA节

        * CDATA节中C表示character是文本字符的意思,CDATA表示纯文本数据;xml中看到CDATA节就知道为纯文本,在CDATA节中写什么都可以

<bean id="studentSeven" class="com.gz.spring.pojo.Student">
        <property name="name">
            <value><![CDATA[ a < b ]]></value>
        </property>
    </bean>

4.xml进行自动装配

* 注意:自动装配时只能将实现类写入bean的class中,不能写接口;并且配置文件中是通过set方法为类的成员变量赋值的

* 自动装配的概念:根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean所依赖的类类型或接口类型属性赋值

* 三层业务架构:控制层中调用service处理业务逻辑,service中调用dao实现持久化操作(注意,调用过程中要实现set方法,因为自动装配底层使用的是set方法进行赋值

* 自动装配的策略:通过bean标签中对autowire设置

    * no、defalut:表示不装配,即bean中的属性不会自动匹配某个bean为属性赋值。此时属性使用默认值

    * byType:根据类型自动为当前属性匹配到某一个bean赋值(用得多)

        * 注意:当使用byType实现自动装配时,IOC容器中有且只有一个类型匹配的bean能够为属性赋值

        * 若通过类型未找到任何一个bean,此时不装配使用默认值

        * 若通过类型找到多个bean、此时报错:NoUniqueBean

    * byName(用得少):btType不行的时候用;将要赋值的属性的属性名作为bean的id在IOC容器中匹配某个bean,为属性赋值

    * 当类型匹配的bean有多个时,此时可以使用byName实现自动装配

* 基于xml的自动装配用的并不多,一般用得多的是基于注解的自动装配

    * 这是因为基于xml的自动装配是对于所有的属性进行的,无法对其中某些属性单独赋值。而基于注解的自动装配,可以只为加上注解的成员变量进行自动装配

<!--
    基于xml进行自动装配的步骤:
    1.存在一个目标接口和目标实现类
        注意:调用类时需要实现set方法,因此基于xml的ioc管理bean是通过set方法进行依赖注入的
    2.在bean标签中的autowire属性进行设置
        a>byType:通过类型进行自动装配
        b>byName:通过属性名进行自动装配
-->

    <bean id="userController" class="com.gz.spring.controller.UserController" autowire="byType"></bean>

    <bean id="userService" class="com.gz.spring.service.impl.UserServiceImpl" autowire="byType"></bean>

    <bean id="userDao" class="com.gz.spring.dao.impl.UserDaoImpl"></bean>

</beans>

 三、Spring管理bean的第二种方式-注解

1.注解的本质

        和xml配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能执行具体操作。

* 本质上来说,所有的操作都是Java代码完成的,xml和注解只是告诉框架的Java代码如何执行

2.扫描组件

        Spring为了知道程序员在哪些地方标记了什么注解,需要通过扫描的方式进行检测,然后根据注解进行后续操作。

<!--    扫描组件-->
<context:component-scan base-package="com.gz.spring.annotation">
</context:component-scan>

3.标识组件的常用注解

- 注意:注解要加到实现类上

* @Component:将类标识为普通组件

* @Controller:将类标识为控制层组件

* @Service:将类标识为业务层组件

* @Repository:将类标识为持久层组件

* 四个注解功能一样,只是名字不一样,这是为了开发人员看的

4.SSM整合时出现的问题

        Spring和Spring MVC是放在一起使用的,Spring MVC需要扫描的是控制层,Spring需要扫描的是除控制层以外所有的组件。这该如何实现呢?

* 在context中使用exclude- filter,排除扫描(用得多)

* type:设置排除扫描的方式

    * annotation:根据注解的类型进行排除;在expression中设置排除的注解的全类名

    * assignable:根据类的类型进行排除;在expression中设置排除的类的全类名

<!--    使用排除扫描-->
    <context:component-scan base-package="com.gz.spring">
<!--        type:排除扫描的方式
                annotation:根据注解类型排除
                assignable:根据类的类型排除
-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:exclude-filter>
        <context:exclude-filter type="assignable" expression="com.gz.spring.controller.UserController"></context:exclude-filter>
    </context:component-scan>

* 在context中使用include-context:包含扫描(用的不多)

    * 注意:需要在context:component-scan标签中设置use-defalut-filters为false;即取消默认的扫描所有类功能,此时才可以使用包含扫描

    * 当use-defalut-filters为true(默认)时,可以使用排除扫描

* type与上相同

* 通过注解+扫描所配置的bean的id,默认值为类的小驼峰:类名的首字母为小写的结果

* 自定义设置bean的id:可以通过标识组件的注解的value属性值设置

@Controller("controller")
public class UserController {
}

5.基于注解的自动装配

* 步骤如下:

    * 第一步:类上要写上相对应的注解,以便扫描

    * 第二步:在成员变量上标记@Autowired注解即可完成自动装配,不需要再提供set方法(在项目中也如此用)

<!--
    基于注解管理bean步骤:
    1.在映射文件中填写好扫描组件(固定的,记住)
    2.将不同实现类对应的注解加入到类上:为了扫描,以便ioc容器进行管理
    3.在成员变量上标记@Autowired注解,不需要再提供set方法
-->
<!--    1.扫描组件-->
    <cotext:component-scan base-package="com.gz.spring"></cotext:component-scan>
//2.将实现类标记为相应标签,以便ioc容器扫描(可以不用在像xml一样写bean)
@Service
public class UserServiceImpl implements UserService {

    //3.在成员变量上标记@AutoWired注解,而不再需要提供set方法
    @Autowired
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void saveUser() {
        userDao.saveUser();
    }
}

        1. @Autowired:实现自动装配功能的注解

        2. @Autowired注解其他能够标识的位置

            * 标识在成员变量上,此时不需要设置成员变量的set方法(一般用这个,此时可以不用在创造set方法)

            * 标识在set方法上

            * 标识在为当前成员变量赋值的有参构造器

        3. @Autowired注解的原理

            1. 默认通过byType方式,在ioc容器中通过类型匹配某个bean为属性赋值(一般都是这这个就可以)

            2. 若有多个类型匹配的bean,此时会自动转换为byName的方式实现自动装配的效果;即将要赋值的属性的属性名作为bean的id匹配某个bean为属性赋值

            3. 若byType和byName的方式都无法实现自动装配,即IOC容器中有多个类型匹配的bean,且这些bean的id和要赋值的属性的属性名都不一致,此时会抛出异常:

NoUniqueBeanDefinitionException

(这种情况几乎不会发生,一般默认byType就能处理,因为一个类型的bean不会在ioc容器中存在多个)

            4. 若出现以上情况则可以在要赋值的属性上,添加一个注解@Qualifier;通过该注解的value属性值,指定某个bean的ID,将这个bean为属性赋值

        4. 若ioc容器中没有任何一个类型匹配的bean,此时抛出异常:noSucnBean;

            * 这是因为在@Autowired注解中有一个属性required,默认值为true,要求必须完成自动装配;

            * 若将required设置为false,此时能装配则装配,无法装配则使用属性的默认值