Spring使用之IOC

      这一段纯属废话,能够不用看........,兑现诺言,每周写一篇博客。最近除了学习算法,还有想更全面了解Spring框架的使用。因而开始了个人学习之旅。因为本人工做中接触的是一个很是很是老的项目,因此对Spring的了解仅仅停留在一些基本的使用上。为加深了解Spring提供的功能,因而就果断买了《Spring实战》,初略看下来,收获仍是有的,但总感受也不是特别特别优秀的书。接下来,我就来谈谈我对Spring的一点浅薄理解。web

1、Spring第一印象

      对于Java后端开发来讲,Spring基本是再熟悉不过的框架了,甚至能够说,如今不用Spring框架进行开发的JAVA后端项目应该基本是百里挑一(我的猜想)。相信一提到Spring,你们想到的就是DI(Dependency Injection)/IOC(Inversion of Control)、AOP这些名词了,没错,这就是Spring提供的核心功能。DI、IOC说的就是同一个功能,翻译过来分别是依赖注入、控制反转,其实就是咱们把对象的建立、销毁、维护交给Spring,让它帮咱们管理这些对象,但咱们须要的时候,让它直接给咱们一个,不须要咱们本身去new。AOP就是面向切面编程。额额,看着这些名词一脸懵逼.................................算法

接下来就来个小例子看看这到底能干吗,能给咱们编程提供什么样的帮助。。spring

在给小例子以前咱们得先了解两个概念:apache

一、既然要让Spring帮咱们建立管理对象、那咱们就得先告诉Spring怎么去建立这些对象,还有对象之间是什么关系。Spring提供了3个方案来实现:一、XML中显式配置。二、Java中显式配置。三、自动包扫描编程

二、Spring提供了俩种容器类型,分别为BeanFactory、ApplicationContext。BeanFactory只提供了基本的DI支持,ApplicationContext基于BeanFactory构建,能提供更多服务。后端

Spring上下文,就是一种容器,继承自ApplicationContext,提供更多功能,如常见的,bash

AnnotationConfigApplicationContext可从JAVA配置类中加载上下文app

ClassPathXmlApplicationContext 从类路径下的XML文件中加载上下文。框架

FileSystemXmlApplilcationContext 从文件系统路径中加载上下文maven

例子

接下来咱们用Idea编辑器,经过maven工具建立一个maven项目来体验下Spring。建立完以后咱们首先要引入Spring jar包,经过maven,咱们不须要本身去下载,只须要在配置文件中配置咱们须要用到的jar包。项目结构以下图


以后咱们在pom.xml文件中配置须要用到的jar文件,咱们将spring的几个核心包配置进来。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>cn.springstudy</groupId>
  <artifactId>luckyspring</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>luckyspring</name>
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <!-- spring 版本  -->
    <org.springframework.version>4.0.0.RELEASE</org.springframework.version>
  </properties>
  <dependencies>
    <!-- 当前项目用到的3个核心spring jar包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${org.springframework.version}</version>
    </dependency

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

</project>
复制代码

如今假设咱们有一个公司,一个公司里面得有雇员来工做,才能让公司提供服务,因而咱们建立雇员类

package cn.springstudy.vo;

public class Employee {

    public void work(){
        System.out.println("Employ start to Work");
    };
}复制代码

再建立公司类

package cn.springstudy.vo;

public class Company {

    //公司类有个雇员对象
    private Employee employee;

    public void  supportService(){
        employee.work();
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}复制代码

前面咱们说过告诉Spring怎么去建立对象有三种方式

方式一XML配置来告诉spring怎么去建立咱们的雇员还有公司类,在建立一个applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置一个对象 指定该对象id为emplayee-->  
    <bean id="employee" class="cn.springstudy.vo.Employee"></bean>
    <!--配置对象,以后往对象中放入一个Employee对象
       ref="employee"表示注入的对象为spring容器中id为employee的对象,这样配置后建立Company
       对象后,会自动调用setEmployee()方法放入一个Employee对象
    -->    
    <bean id="company" class="cn.springstudy.vo.Company">
        <property name="employee" ref="employee"></property>
    </bean>
</beans>复制代码

接下来咱们建立一个main函数做为程序的入口,在main函数中去建立Spring容器

package cn.springstudy.spring;

import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringStudy {
    public static void main(String arg[]){
        //方式一,XML文件中加载上下文,即Spring容器
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器中获取一个Company对象
        Company company = (Company) classPathXmlApplicationContext.getBean("company");
        company.supportService();
    }
}复制代码

执行一下,控制台打印以下


咱们能够看到咱们执行company.supportService()竟然没报空指针,要知道咱们可没在Company类中去建立Empoyee对象,说明什么???Spring容器自动帮咱们建立Employee对象并set到Company对象中了。

方式二

建立一个配置Java类

package cn.springstudy.spring;

import cn.springstudy.vo.Company;
import cn.springstudy.vo.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//注解,代表这个是一个Spring配置类
@Configuration
public class SpringConfig {

 //Spring容器管理的类,经过Bean注解,方法名即默认为bean的id,也可在Bean注解后加参数指定Bean的ID
    @Bean
    public Employee employee(){
        return  new Employee();
    }
    //Spring容器管理的类,经过Bean注解
    @Bean
    public Company company(){
        Company company =  new Company();
        company.setEmployee(employee());
        return  company;
    }
}
复制代码

main函数,程序入口,执行结果同上

package cn.springstudy.spring;

import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringStudy {

    public static void main(String arg[]){

        //方式二,默认bean的名称即为配置方法的名称,须要用到AnnotationConfigApplicationContext容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(SpringConfig.class);
        annotationConfigApplicationContext.refresh();
        Company company1 = (Company) annotationConfigApplicationContext.getBean("company");
        company1.supportService();
    }
}复制代码

方式3、

方式三序借助方式一或者方式二,咱们首先须要在须要被Spring容器管理的类上面加上@Component注解,因此咱们在Empoyee加上注解

package cn.springstudy.vo;

import org.springframework.stereotype.Component;

@Component
public class Employee {

    public void work(){
        System.out.println("Employ start to Work");
    };
}复制代码

Company类上加上注解,需自动分配的对象上加@Autowired注解

package cn.springstudy.vo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Company {

    //Autowired,帮我分配个Employee对象过来。
    @Autowired
    private Employee employee;

    public void  supportService(){
        employee.work();
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}复制代码

在配置类上加上包自动扫描路径

package cn.springstudy.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//cn.springstudy.vo 为扫描的基础包路径
@Configuration
@ComponentScan("cn.springstudy.vo")
public class SpringConfigScan {
}复制代码

测试main方法

package cn.springstudy.spring;

import cn.springstudy.vo.Company;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringStudy {

    public static void main(String arg[]){    
        //方式三,需借助方式2
        AnnotationConfigApplicationContext annotationConfigApplicationContext2 = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext2.register(SpringConfig.class);
        annotationConfigApplicationContext2.refresh();
        Company company2 = (Company) annotationConfigApplicationContext.getBean("company");
        company2.supportService();
    }
}复制代码

执行结果同上。

XML、Java配置文件混着使用

固然XML配置方式和Java配置文件还能混着用。

一、在XML配置中混用Java配置文件只需在配置文件中增长一个<bean></bea>便可将Java配置类导入XML配置中。二、XML中导入其余XML配置,只需用<import>指定其余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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--导入其余XML配置文件  -->
    <import resource="applicationContext2.xml"></import>
    <!--Spring Java配置类-->
    <bean class="cn.springstudy.spring.SpringConfig"></bean>
    
    <bean id="employee" class="cn.springstudy.vo.Employee"></bean>
    <bean id="company" class="cn.springstudy.vo.Company">
        <property name="employee" ref="employee"></property>
    </bean>
    
</beans>复制代码

一、Java配置文件混着XML配置文件,只需在Java类中加个注解便可,二、Java配置类导入其余配置类,只需加@Import注解,指定配置类位置。

package cn.springstudy.spring;

import cn.springstudy.vo.Company;
import cn.springstudy.vo.Employee;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
//导入其余XML配置文件
@ImportResource("classpath:applicationContext.xml")
//导入其余配置类
@Import({SpringConfigScan.class})
public class SpringConfig {    
    @Bean
    public Employee employee(){
        return  new Employee();
    }

    @Bean
    public Company company(){
        Company company =  new Company();
        company.setEmployee(employee());
        return  company;
    }
}复制代码

Spring DI初步使用方法已经如上,接下来咱们主要经过XML配置的方式来讲明其余功能。

构造方法注入依赖对象

以上的小例子中Company中的Employee对象是经过setEmployee方法配置进去的。咱们还能够经过构造方法的形式配置进去。

给Company类增长一个构造方法

package cn.springstudy.vo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

public class Company {

    private Employee employee;
    private String name;

    public Company(Employee employee,String name){
        this.employee = employee;
        this.name = name;
    }
    public void  supportService(){
        employee.work();
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}复制代码

配置文件配置以下

<?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:c="http://www.springframework.org/schema/c" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/c http://www.springframework.org/schema/c/spring-c.xsd">
    <!--在上面beans中声明spring中c命名空间-->

    <bean id="employee" class="cn.springstudy.vo.Employee"></bean>
   <!-- 构造方法中注入Employee对象,还有一个名称其中
    c:为命名空间前缀
    emplayee、name分别为构造函数中参数的名称
     -ref表示注入的是spring容器中的对象
    "emplayee"表示引入的是id为emplayee的对象,name没有带-ref则是注入字符串juejin.com
   -->
    <bean id="company" class="cn.springstudy.vo.Company"
        c:employee-ref="employee"
        c:name="juejin.com">
    </bean>

</beans>复制代码

工厂方法模式建立对象

以上说明Spring的依赖注入的基本使用。咱们在编程时候可能不是经过new来建立对象,有时也会使用静态方法(静态工厂模式)来建立对象,那么Spring是否支持呢?答案是确定的。

public class ClientService {
    private ClientService() {}

    public static ClientService createInstance() {
        return new ClientService()
    }
}复制代码

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>复制代码

固然工厂方法模式是经过非经过静态方法建立对象的,Spring也是支持的,以下

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}复制代码

<!-- 工厂类  -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
</bean>
<!--  ClientService类配置 -->
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>复制代码

Spring中bean的做用域

默认状况下,Spring容器中的bean都是单例的,能够经过配置修改。spring定义了多种做用域:

一、Singleton(默认) 单例

二、Prototype 原型,每次经过容器获取对象都会建立一个新对象、

三、Session 会话,一个web会话中使用一个对象

四、Request ,每次web请求使用一个对象

经过XML配置可在bean中指定scrop属性指定

Java配置类可在方法上加注解@Scope("prototype")

自动扫描的类可在类上加注解@Scope("prototype")

<!-- scope 属性指定做用域 -->
<bean id="employee" class="cn.springstudy.vo.Employee"  scope="prototype"></bean>复制代码

@Component
@Scope("prototype")
public class Company {.....}复制代码

@Configuration
public class SpringConfig {
    @Bean
    @Scope("prototype")
    public Employee employee(){
        return  new Employee();
    }
}复制代码


最后,感受这篇写得有点乱,也很基础,还有不少东西没说到,不知道看到这里的人儿有无收获,说好的一周一篇,额,那就先发出来吧,之后可能还作修改,待续。。

相关文章
相关标签/搜索