前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring详解篇之IoC控制反转

Spring详解篇之IoC控制反转

作者头像
方志朋
发布2017-12-29 16:06:26
1.4K0
发布2017-12-29 16:06:26
举报
文章被收录于专栏:史上最简单的Spring Cloud教程

一.Spring概况

  • spring是一个开源框架
  • 是一个轻量的控制反转和面向切面的容器框架
  • 大小和开销都是轻量的。
  • 通过控制反转技术可以达到松耦合的目的
  • 切面编程,允许通过分离应用的业务逻辑。
  • 包含并管理应用对象的配置和生命周期,是一个容器,并且能够组装。

二、IoC

ioc控制反转:控制权转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责和维护。ioc的目的是创建对象并且组装对象之间的关系。

1.bean容器初始化
  • –org.springframework.beans
  • –org.springframework.context
  • beanfactory 提供配置结构和基本功能,加载并初始化bean
  • applicationContext 保存bean对象并在应用中被应用
2.spring注入:
  • spring 注入是指在启动 spring容器加载bean配置的时候,完成对变量的赋值行为。
  • 常见的注入方式:设值注入、构建注入

举个例子,构建注入

dao层

代码语言:javascript
复制
public interface InjectionDAO {

    public void save(String arg);

}



public class InjectionDAOImpl implements InjectionDAO {

    public void save(String arg) {
        //模拟数据库保存操作
        System.out.println("保存数据:" + arg);
    }

}

service 层接口:

代码语言:javascript
复制
public interface InjectionService {

    public void save(String arg);

}

service 层实现:

代码语言:javascript
复制
public class InjectionServiceImpl implements InjectionService {

    private InjectionDAO injectionDAO;

    //构造器注入
    public InjectionServiceImpl(InjectionDAO injectionDAO1) {
        this.injectionDAO = injectionDAO1;
    }

    //设值注入
    public void setInjectionDAO(InjectionDAO injectionDAO) {
        this.injectionDAO = injectionDAO;
    }

    public void save(String arg) {
        //模拟业务操作
        System.out.println("Service接收参数:" + arg);
        arg = arg + ":" + this.hashCode();
        injectionDAO.save(arg);
    }

在spring xml中的配置

代码语言:javascript
复制
<?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="injectionService" class="com.forezp.ioc.injection.service.InjectionServiceImpl">
            <constructor-arg name="injectionDAO1" ref="injectionDAO"></constructor-arg>
        </bean>

        <bean id="injectionDAO" class="com.forezp.ioc.injection.dao.InjectionDAOImpl"></bean>

 </beans>

单元测试

本系列文章单元测试基类

代码语言:javascript
复制
public class UnitTestBase {

    private ClassPathXmlApplicationContext context;

    private String springXmlpath;

    public UnitTestBase() {}

    public UnitTestBase(String springXmlpath) {
        this.springXmlpath = springXmlpath;
    }

    @Before
    public void before() {
        if (StringUtils.isEmpty(springXmlpath)) {
            springXmlpath = "classpath*:spring-*.xml";
        }
        try {
            context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));
            context.start();
        } catch (BeansException e) {
            e.printStackTrace();
        }
    }

    @After
    public void after() {
        context.destroy();
    }

    @SuppressWarnings("unchecked")
    protected <T extends Object> T getBean(String beanId) {
        try {
            return (T)context.getBean(beanId);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }

    protected <T extends Object> T getBean(Class<T> clazz) {
        try {
            return context.getBean(clazz);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }

}

单元测试:

代码语言:javascript
复制
@RunWith(BlockJUnit4ClassRunner.class)
public class TestInjection extends UnitTestBase {

    public TestInjection() {
        super("classpath:spring-injection.xml");
    }

    @Test
    public void testSetter() {
        InjectionService service = super.getBean("injectionService");
        service.save("这是要保存的数据");
    }

    @Test
    public void testCons() {
        InjectionService service = super.getBean("injectionService");
        service.save("这是要保存的数据");
    }

}

运行打印:

>

Service接收参数:这是要保存的数据 保存数据:这是要保存的数据:1247298779

这个例子说明,我们可以通过ClassPathXmlApplicationContext.getBean()获取到了service,这个service 是通过xml配置注入到容器中,并且注入的时候通过构造函数的设置了成员变量dao。

三.bean的配置项

3.1 bean常见的配置项,如下:
  • Id
  • Class
  • Scope
  • Constructor arguments
  • Properties
  • Autowiring mode
  • lazy-initialization mode
  • Initialization/destruction method
3.2 bean的作用域
  • singleton: 单列
  • prototype每次使用都会创建新实例
  • request :每次http请求创建一个实例,仅在当前 request有效
  • session : 当前session有效

举个例子: 测试sinleton和prototype

创建bean实例

代码语言:javascript
复制
public class BeanScope {

    public void say() {
        System.out.println("BeanScope say : " + this.hashCode());
    }

}

在xml中配置,作用域为singleton

代码语言:javascript
复制
<?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="beanScope" class="com.imooc.bean.BeanScope" scope="singleton"></bean>

 </beans>

单元测试:

代码语言:javascript
复制
@RunWith(BlockJUnit4ClassRunner.class)
public class TestBeanScope extends UnitTestBase {

    public TestBeanScope() {
        super("classpath*:spring-beanscope.xml");
    }

    @Test
    public void testSay() {
        BeanScope beanScope = super.getBean("beanScope");
        beanScope.say();

        BeanScope beanScope2 = super.getBean("beanScope");
        beanScope2.say();
    }


}

运行单元测试:

>

BeanScope say : 1113008012 BeanScope say : 1113008012

在xml中配置,作用域为prototype

代码语言:javascript
复制
<?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="beanScope" class="com.imooc.bean.BeanScope" scope="prototype"></bean>

 </beans>

运行单元测试

>

BeanScope say : 144724468 BeanScope say : 1432645272

由此可发现sington在bean容器是一个实例,而prototype创建了二个实例。

四.bean的生命周期

包括以下几个方面:

  • 定义,在xml中配置
  • 初始化
  • 使用
  • 销毁
初始化

有两种方式

  • 实现 InitializingBeean接口,覆盖afterPropertiesSet()
  • 配置init-method方法
销毁

也有两种方式:

  • 实现DisposableBean接口,覆盖destroy();
  • 配置 destroy-method

举个例子:

创建bean实例:

代码语言:javascript
复制
public class BeanLifeCycle implements InitializingBean, DisposableBean {

    public void defautInit() {
        System.out.println("Bean defautInit.");
    }

    public void defaultDestroy() {
        System.out.println("Bean defaultDestroy.");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Bean destroy.");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean afterPropertiesSet.");
    }

    public void start() {
        System.out.println("Bean start .");
    }

    public void stop() {
        System.out.println("Bean stop.");
    }

}

bean的配置:

代码语言:javascript
复制
<?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-init-method="defautInit" default-destroy-method="defaultDestroy">

        <bean id="beanLifeCycle" class="com.imooc.lifecycle.BeanLifeCycle"  init-method="start" destroy-method="stop"></bean>

 </beans>

单元测试:

代码语言:javascript
复制
@RunWith(BlockJUnit4ClassRunner.class)
public class TestBeanLifecycle extends UnitTestBase {

    public TestBeanLifecycle() {
        super("classpath:spring-lifecycle.xml");
    }

    @Test
    public void test1() {
        super.getBean("beanLifeCycle");
    }

}

运行:

Bean afterPropertiesSet. Bean start . Bean destroy. Bean stop.

同时实现两种方式的初始化方法的执行顺序: 接口实现优先于xml中的配置。

五.bean的自动装配(Autowiring)

  • No: 不做任何操作
  • byname:根据属性名自动装配
  • byType:如果容器存在一个与指定类型相同的bean,则自动装配,如果存在多个,则抛出异常。
  • constructor:与 byType类似,不同之处它在于构造器的参数。

举例子: 1.byName方式:

创建一个dao:

代码语言:javascript
复制
public class AutoWiringDAO {

    public void say(String word) {
        System.out.println("AutoWiringDAO : " + word);
    }

}

创建一个service

代码语言:javascript
复制
public class AutoWiringService {

    private AutoWiringDAO autoWiringDAO;


    public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
        System.out.println("setAutoWiringDAO");
        this.autoWiringDAO = autoWiringDAO;
    }

    public void say(String word) {
        this.autoWiringDAO.say(word);
    }

}

在xml中配置:

代码语言:javascript
复制
<?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-autowire="byName">

        <bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>

        <bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO" ></bean>

 </beans>

单元测试:

代码语言:javascript
复制
@RunWith(BlockJUnit4ClassRunner.class)
public class TestAutoWiring extends UnitTestBase {

    public TestAutoWiring() {
        super("classpath:spring-autowiring.xml");
    }

    @Test
    public void testSay() {
        AutoWiringService service = super.getBean("autoWiringService");
        service.say(" this is a test");
    }

}

运行:

setAutoWiringDAO AutoWiringDAO : this is a test

通过default-autowire=”byName”; AutoWiringService 自动获取了autoWiringDAO的实例。

2.byTYpe

将在xml中配置改为byType :

代码语言:javascript
复制
<?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-autowire="byName">

        <bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>

        <bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO" ></bean>

 </beans>

其他不变,运行和byName 一样。

3.constructor

代码语言:javascript
复制
<?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-autowire="constructor">

        <bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>

        <bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO" ></bean>

 </beans>

AutoWiringService 中增加构造器

代码语言:javascript
复制
public class AutoWiringService {

    private AutoWiringDAO autoWiringDAO;

    public AutoWiringService(AutoWiringDAO autoWiringDAO) {
        System.out.println("AutoWiringService");
        this.autoWiringDAO = autoWiringDAO;
    }

    public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
        System.out.println("setAutoWiringDAO");
        this.autoWiringDAO = autoWiringDAO;
    }

    public void say(String word) {
        this.autoWiringDAO.say(word);
    }

}

允行:

AutoWiringDAO : this is a test

六.classPath扫描与组件管理

从spring 3.0开始,spring javaConfig 项目提供了许多特性,包括使用java而不是xml

1.比如注解

@Configuration @Bean @Import @DependsOn @Component 是一个通用注解,应用于任何bean @Reposity注解DAO @Service注解service @Controller注解controller

2.spring可以自动检测类并注册bean到applicationContext中。比如 @Service @Reposity等

3.< context:annoation-config />会查找applicationContext中bean的注解。

扫描 :< context:component-scan> 包含< context:annoation-config/>,通常只需要使用前者。

代码语言:javascript
复制
<context:component-scan base-package="com.forezp" > 

举个例子: 通过扫描获取bean,在xml中的配置:

代码语言:javascript
复制
<?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" >

        <context:component-scan base-package="com.forezp.beanannotation"></context:component-scan>

 </beans>

定义一个bean类: 其中scope 注解表示bean的作用域,默认singleton。Component默认类名并将第一个字母小写。

代码语言:javascript
复制
@Scope
@Component
public class BeanAnnotation {

    public void say(String arg) {
        System.out.println("BeanAnnotation : " + arg);
    }

    public void myHashCode() {
        System.out.println("BeanAnnotation : " + this.hashCode());
    }

}

单元测试:

代码语言:javascript
复制
@RunWith(BlockJUnit4ClassRunner.class)
public class TestBeanAnnotation extends UnitTestBase {

    public TestBeanAnnotation() {
        super("classpath*:spring-beanannotation.xml");
    }

    @Test
    public void testSay() {
        BeanAnnotation bean = super.getBean("beanAnnotation");
        bean.say("This is test.");

        //bean = super.getBean("bean");
        //bean.say("This is test.");
    }

}

运行:

BeanAnnotation : This is test.

七、Autowired

  • @Autowired可以用于setter方法上
  • 可以用于成员变量
  • 可以用于构造器

举个例子:

采用包扫描:

代码语言:javascript
复制
<?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" >

        <context:component-scan base-package="com.forezp.beanannotation"></context:component-scan>

 </beans>

采用注解:DAO层

代码语言:javascript
复制
@Repository
public class InjectionDAOImpl implements InjectionDAO {

    public void save(String arg) {
        //模拟数据库保存操作
        System.out.println("保存数据:" + arg);
    }

}

service层:

代码语言:javascript
复制
@Service
public class InjectionServiceImpl implements InjectionService {

//  @Autowired
    private InjectionDAO injectionDAO;

    @Autowired
    public InjectionServiceImpl(InjectionDAO injectionDAO) {
        this.injectionDAO = injectionDAO;
    }

//  @Autowired
    public void setInjectionDAO(InjectionDAO injectionDAO) {
        this.injectionDAO = injectionDAO;
    }



    public void save(String arg) {
        //模拟业务操作
        System.out.println("Service接收参数:" + arg);
        arg = arg + ":" + this.hashCode();
        injectionDAO.save(arg);
    }

}

单元测试:

“` @RunWith(BlockJUnit4ClassRunner.class) public class TestInjection extends UnitTestBase {

代码语言:javascript
复制
public TestInjection() {
    super("classpath:spring-beanannotation.xml");
}

@Test
public void testAutowired() {
    InjectionService service = super.getBean("injectionServiceImpl");
    service.save("This is autowired.");
}

}

“`

运行:

Service接收参数:This is autowired. 保存数据:This is autowired.:1641742937

八、基于java的容器注解@Bean

  • @Bean 标识一个用于配置和初始化一个由springIoC容器管理的新对象的方法,类似于 xml配置文件的

举个例子: 用注解去代替xml文件

代码语言:javascript
复制
@Configuration

public class StoreConfig {


@Bean(name = "stringStore", initMethod="init", destroyMethod="destroy")
    public Store stringStore() {
        return new StringStore();
    }

javabean StringStore类

代码语言:javascript
复制
public class StringStore implements Store<String> {

    public void init() {
        System.out.println("This is init.");
    }

    public void destroy() {
        System.out.println("This is destroy.");
    }

}

单元测试:

代码语言:javascript
复制
@RunWith(BlockJUnit4ClassRunner.class)
public class TestJavabased extends UnitTestBase {

    public TestJavabased() {
        super("classpath*:spring-beanannotation.xml");
    }

    @Test
    public void test() {
        Store store = super.getBean("stringStore");
        System.out.println(store.getClass().getName());
    }

    }

另外可以用ImportResource注解类获取资源文件信息:

代码语言:javascript
复制
@Configuration
@ImportResource("classpath:config.xml")
public class StoreConfig {


    @Value("${url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${password}")
    private String password;

九、JSR-250

  • spring支持jsr-250
  • @Resource注解变量或者setter 方法
  • Resource注解有一个name属性,默认该值作为被注入bean的名称。

举个例子:

Dao层:

代码语言:javascript
复制
@Repository
public class JsrDAO {

    public void save() {
        System.out.println("JsrDAO invoked.");
    }

}

service层:

代码语言:javascript
复制
@Service
public class JsrServie {

    @Resource
    private JsrDAO jsrDAO;

//  @Resource
//  public void setJsrDAO(@Named("jsrDAO") JsrDAO jsrDAO) {
    //  this.jsrDAO = jsrDAO;
    //}

    @PostConstruct
    public void init() {
        System.out.println("JsrServie init.");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("JsrServie destroy.");
    }

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

}      
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-03-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.Spring概况
  • 二、IoC
    • 1.bean容器初始化
      • 2.spring注入:
      • 三.bean的配置项
        • 3.1 bean常见的配置项,如下:
          • 3.2 bean的作用域
          • 四.bean的生命周期
            • 初始化
              • 销毁
              • 五.bean的自动装配(Autowiring)
              • 六.classPath扫描与组件管理
              • 七、Autowired
              • 八、基于java的容器注解@Bean
              • 九、JSR-250
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档