Spring4——IOC/DI

来源:互联网 发布:apache 开启https 编辑:程序博客网 时间:2024/05/22 02:25

1 Spring概述

  • 轻量级:Spring是非侵入性的——基于Spring的开发不需要实现Spring的接口,不用继承任何父类
  • 依赖注入(Dependancy Injection, DI),或反转控制(Inversion of Control, IOC)
  • 面向切面编程(AOP——Aspect Oriented Programming)
  • 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
  • 框架:Spring实现了使用简单的组件配置组合成一个复杂的应用,在Spring中可以使用XML和Java注解组合这些对象
  • 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库

2 IOC和DI
IOC的思想是反转资源获取的方向。容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源。
DI——IOC的另一种表述方式:组件以一些预先设定好的方式(如setter方法)接受来自如容器的资源注入。

3 配置bean:
3.1 基于XML文件的方式配置bean
① 配置形式:基于XML文件的方式;基于注解的方式
② Bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法&实例工厂方法)、FactoryBean
③ IOC容器:ApplicationContext
ApplicationContext接口

  • ApplicationContext的主要实现类:ClassPathXmlApplicationContext:从类路径下加载配置文件,以及FileSystemXmlApplicationContext:从文件系统中加载配置文件。
  • ConfigurableApplicationContext扩展于ApplicationContext,新增两个主要方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的功能。
  • ApplicationContext在初始化上下文时就实例化所有单例Bean。
  • WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

④ 依赖注入的方式:属性注入,构造器注入

  属性注入

  • 属性注入即通过setter方法注入bean的属性值或依赖的对象
  • 属性注入使用<property>元素,使用name属性指定Bean的属性名称,value属性或<value>子节点指定属性值
  • 属性注入是实际应用中最常用的注入方式。
    <bean id="helloWorld" class="com.zc.spring.beans.HelloWorld">        <property name="name" value="Spring"></property>    </bean>

  
  构造方法注入

  • 通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后可以使用。
  • 构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性。
    <!-- 使用构造器注入属性值可以指定参数的位置和参数的类型,以区分重载的构造方法-->    <bean id="car" class="com.zc.spring.beans.Car">        <constructor-arg value="Audi" index="0"></constructor-arg>        <constructor-arg index="1">            <!--如果字面值包含特殊字符可以使用<![CDATA[]]> 包裹起来-->            <!--属性值也可以使用value子节点进行配置-->            <value><![CDATA[<ShangHai^>]]></value>        </constructor-arg>        <constructor-arg type="double">            <value>3000</value>        </constructor-arg>    </bean>    <bean id="car2" class="com.zc.spring.beans.Car">        <constructor-arg value="Baoma" type = "java.lang.String"></constructor-arg>        <constructor-arg value="Shanghai" type="java.lang.String" ></constructor-arg>        <constructor-arg value="200" type="int"></constructor-arg>    </bean>

引用其他Bean:组成应用程序的Bean经常需要相互协作以完成应用程序的功能。在Bean的配置文件中,通过<ref>或ref属性为Bean的属性或构造器参数指定对Bean的引用,使得Bean能够互相访问。也可以在属性或构造器里包含Bean的声明,这样的Bean成为内部Bean。

内部Bean:当Bean实例仅仅给一个特定的属性使用时,可以将其声明为内部Bean。内部Bean声明直接包含在< property>或< constructor-arg>元素里,不需要设置任何id或name属性。内部Bean不能使用在其他任何地方。

    <bean id="person" class="com.zc.spring.beans.Person">        <property name="name" value="Tom"></property>        <property name="age" value="18"></property>        <!--使用property的ref属性建立bean之间的引用关系-->        <!--        <property name="car" ref="car2"></property>        -->        <!--使用<ref>子节点或ref属性都可以        <property name="car">            <ref bean = "car2" />        </property>        -->        <!--内部bean,不能被外部引用,只能在内部使用-->        <property name="car">            <bean class="com.zc.spring.beans.Car">                <constructor-arg value="Ford"></constructor-arg>                <constructor-arg value="Changan"></constructor-arg>                <constructor-arg value="200000" type="double"></constructor-arg>            </bean>        </property>    </bean>    <bean id="person2" class="com.zc.spring.beans.Person">        <constructor-arg value="Jerry"></constructor-arg>        <constructor-arg value="25"></constructor-arg>        <constructor-arg ref="car"></constructor-arg>    </bean>

3.2 基于注解的方式配置bean
① 在classpath中扫描组件

  • 组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件。
  • 特定组件包括:
    -@Component:基本注解,标识一个受Spring管理的组件
    -@Respository:标识持久层组件
    -@Service:标识业务层组件
    -@Controller:标识表现层组件
  • 对于扫描到的组件,Spring有默认的命名策略:其一,使用非限定类名(UserService),第一个字母小写(userService);其二,也可以在注解中通过value属性值标识组件的名称,如UserService是一个接口,可以将接口的实现类UserServiceImpl通过value标识为userService。

Component部分:

package com.zc.spring.beans.annotation;import org.springframework.stereotype.Component;@Componentpublic class TestObject {}

Repository部分:
UserRepository接口:

package com.zc.spring.beans.annotation.repository;public interface UserRepository {    void save();}

UserRepositoryImpl接口实现类:

package com.zc.spring.beans.annotation.repository;import org.springframework.stereotype.Repository;@Repository("userRepository")public class UserRepositoryImpl implements UserRepository {    @Override    public void save() {        System.out.println("UserRepository save...");    }}

Service部分:

package com.zc.spring.beans.annotation.service;import org.springframework.stereotype.Service;@Servicepublic class UserService {    public void add(){        System.out.println("UserService add...");    }}

Contoller部分:

package com.zc.spring.beans.annotation.controller;import org.springframework.stereotype.Controller;@Controllerpublic class UserController {    public void execute(){        System.out.println("UserController execute ");    }}
  • 在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明<context:component-scan>

    -base-packge属性制定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中的所有类。
    -当需要扫描多个包时,可以使用逗号分隔。

beans-annotation.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">    <!--指定Srping IOC容器扫描的包-->    <context:component-scan base-package="com.zc.spring.beans.annotation"></context:component-scan></beans>

以上,测试类为:

package com.zc.spring.beans.annotation;import com.zc.spring.beans.annotation.controller.UserController;import com.zc.spring.beans.annotation.repository.UserRepository;import com.zc.spring.beans.annotation.service.UserService;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {    public static void main(String[] args){          ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");          TestObject to = (TestObject) ctx.getBean("testObject");          System.out.println(to);          UserController userController = (UserController) ctx.getBean("userController");          System.out.println(userController);          UserService userService = (UserService) ctx.getBean("userService");          System.out.println(userService);          UserRepository userRepository = (UserRepository)ctx.getBean("userRepository");          System.out.println(userRepository);    }}

测试结果:通过注解配置了4个bean,分别打印出来。
result

  • 如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类,如:

<context:component-scan base-package="com.zc.spring.beans.annotation" resource-pattern="repository/*.class"></context:component-scan>
  • 子节点context:include-filter标识要包含的目标类,该子节点需要use-default-filters="false"(不使用默认的过滤器)来配合使用
 <context:component-scan base-package="com.zc.spring.beans.annotation" use-default-filters="false">      <!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"></context:include-filter>-->      <context:include-filter type="assignable" expression="com.zc.spring.beans.annotation.repository.UserRepository"></context:include-filter></context:component-scan>
  • context:exclude-filter 子节点指定排除哪些指定表达式的组件
<context:component-scan base-package="com.zc.spring.beans.annotation">   <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"></context:exclude-filter>-->     <context:exclude-filter type="assignable" expression="com.zc.spring.beans.annotation.repository.UserRepository"></context:exclude-filter></context:component-scan>

过滤表达式中type="annotation"表示过滤所有标注了expression表达式表明的类,type="assignable"表示过滤所有继承或扩展expression表达式表明的类。

当Bean和Bean之间有关联关系时

  • 使用@Autowired注解自动装配具有兼容类型的单个Bean 属性如构造方法,普通字段(即使是非public),一切具有参数的方法都可以应用,如:
package com.zc.spring.beans.annotation.controller;import com.zc.spring.beans.annotation.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;@Controllerpublic class UserController {    //UserController和UserService有关联    @Autowired    private UserService userService;    public void execute(){        System.out.println("UserController execute ");        userService.add();    }}
  • 默认情况下,所有使用@Autowired注解的属性都需要被设置。当Spring找不到匹配的Bean装配属性时,会抛出异常,若某一属性允许不被设置,可以设置@Autowired注解的required属性为false。
    若TestObject类为:
package com.zc.spring.beans.annotation;import org.springframework.stereotype.Component;//此处没有注解public class TestObject {}

package com.zc.spring.beans.annotation.repository;import com.zc.spring.beans.annotation.TestObject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;@Repository("userRepository")public class UserRepositoryImpl implements UserRepository {    //设置required=false    @Autowired(required = false)    private TestObject testObject;    @Override    public void save() {        System.out.println("UserRepository save...");        System.out.println(testObject);    }}

测试类:

package com.zc.spring.beans.annotation;import com.zc.spring.beans.annotation.repository.UserRepository;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {    public static void main(String[] args){          ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");          UserRepository userRepository = (UserRepository)ctx.getBean("userRepository");          userRepository.save();    }}

结果:这里写图片描述

  • 默认情况下,当IOC容器存在多个类型兼容的Bean时(如一个接口有多个实现类),通过类型的自动装配将无法工作。此时,除了在注解中通过value属性值标识组件的名称外,还可以在@Qualifier注解里提供Bean的名称,Spring允许对方法的入参标注@Qualifier以指定注入Bean的名称。
import com.zc.spring.beans.annotation.repository.UserRepository;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;@Servicepublic class UserService {    @Autowired    @Qualifier("userRepositoryImpl")    private UserRepository userRepository;//此时接口userRepository有多个实现类    public void add(){        System.out.println("UserService add...");        userRepository.save();    }}

或者

package com.zc.spring.beans.annotation.service;import com.zc.spring.beans.annotation.repository.UserRepository;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;@Servicepublic class UserService {    private UserRepository userRepository;    @Autowired    public void setUserRepository(@Qualifier("userRepositoryImpl") UserRepository userRepository) {        this.userRepository = userRepository;    }    public void add(){        System.out.println("UserService add...");        userRepository.save();    }}
原创粉丝点击