Java框架部分——Spring(IOC)

一、基础概述

Spring框架是一个轻量级的框架,占用内存小。Spring的好处:

  1. 简化Java的开发
  2. 基于POJO轻量级和最小侵入式开发
  3. 通过依赖注入和面向接口实现松耦合
  4. 基于切面和惯例进行声明式编程
  5. 通过切面和模板减少样板式代码

二、体系结构

IOC介绍

spring中提供了IOC容器,IOC(Inversion Of Control) 控制反转:对象的创建交给外部容器完成,这个就是控制反转。spring中使用控制反转来实现对象在不同程序中的使用。容器存在的必要性就是管理对象

通过购买图书的场景来分析使用java实例,使用相关对象是需要new创建并持有。存在的缺点

  1. 实例化一个组件比较困难
    例如:bookservice和userservice要创建DataSource实例,实际上需要读取配置,即config,通过config实例才创建出DataSourceservice。
    其实没有必要用bookservice和UserService都创建DataSourceservice,可以共享DataSourceservice,但又牵扯到谁负责创建DataSourceservice实例,也不好处理。
  2. 很多组件需要销毁来释放资源
    例如datasouce,如果采用共享形式,如何确保使用方能正确地销毁当前资源。
  3. 随着映入到的业务组件越来越多,对组件的共享管理也就越来越复杂
  • 以上问题可以通过提供容器来管理所有的组件(对象)。所有的对象的创建,销毁等操作都交给容器,谁需要使用对象,在容器中获取该对象的使用权。哪一个对象需要,就将使用的对象注入到该对象中。对于使用方而言,只需要关注使用即可,对象的生命周期的管理就交给IOC容器进行管理。
  • IOC容器负责实例化所有的组件,需要进行依赖的对象都交给容器管理,IOC最简单的方式就是通过xml方式来管理
<beans> 
  <!--将数据源交给容器管理-->
  <bean id="datasource" class="DataSourceService" >
  	<!--id:取名字-->
    <bean id="userservice" class="UserService">
       <property name="datasource" ref="datasource"/>
    </bean>  
    <!--bookService也是同样的...-->
</beans>
  • 在BuyService中使用获取用户信息,通过容器:context 提供的方式来获取用户的实例context.getName(“userservice”),就会在容器中找 id=“userservice”,进而获取该对象实例进行使用。

1、IOC思想

对象的创建交给外部容器完成,这个就是控制反转。spring中使用控制反转来实现对象在不同程序中的使用。控制反转解决对象处理的问题,将对象交给容器进行创建

  • 依赖注入(DI):dendendency injection
    对象与对象之间的依赖问题即依赖注入 AOP->DI(依赖注入解决)
  • Spring使用依赖注入来实现对象之间的依赖关系。
    在对象创建之后,对象的关系处理就是依赖注入。
    无论是对象的创建、处理对象之间的依赖关系、对象创建的时间还有对象创建的数量,都可以在spring的IOC容器上配置对象的信息。

Spring管理对象:
(1) 引入核心依赖->集成依赖

<!--spring的核心依赖-->                          
<dependency>                                
  <groupId>org.springframework</groupId>    
  <artifactId>spring-core</artifactId>      
  <version>4.1.7.RELEASE</version>          
</dependency>                               
<dependency>                                
  <groupId>org.springframework</groupId>    
  <artifactId>spring-beans</artifactId>     
  <version>4.1.7.RELEASE</version>          
</dependency>                               
<dependency>                                
  <groupId>org.springframework</groupId>    
  <artifactId>spring-context</artifactId>   
  <version>4.1.7.RELEASE</version>          
</dependency>                               
<dependency>                                
  <groupId>org.springframework</groupId>    
  <artifactId>spring-expression</artifactId>
  <version>4.1.7.RELEASE</version>          
</dependency>                               
<!--log4j-->                                
<dependency>                                
  <groupId>log4j</groupId>                  
  <artifactId>log4j</artifactId>            
  <version>1.2.15</version>                 
</dependency>                               

(2) 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-3.0.xsd">
</beans>   

(3) 创建实体类

  1. 创建需要容器管理的类
public class User {
    private Integer id;
    private String name;
}
  1. 将user对象交给容器管理
<!--使用bean标签类管理对象                  
    id:属性标识对象,不可重复                 
    class属性代表要管理的对象的全路径            
-->                                
<bean id="user" class="bean.User"/>

(4) 通过容器来获取User对象

public class App {
    public static void main( String[] args ) {
        //获取IOC容器,通过读取 classpath路径下的spring的配置文件
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationcontext.xml");
        //在IOC容器获取需要的对象实例
        User user = (User) applicationContext.getBean("user");
        System.out.println(user);
    }
} 

运行结果:
在这里插入图片描述

  • 这里在运行时,如果遇到了以下错误:
    在这里插入图片描述需要在 pom.xml 文件中引入spring依赖的 commons-logging-1.1.3.jar 文件:
    我先引入的 1.2 版本,依旧报错,改成 1.1.3 版本问题解决。
<dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.3</version>
    </dependency>
  • 原来获取User对象时,通过new User() ,现在将对象的全路径配置在容器中,容器该如何创建对象呢?
    -> 反射 -> IOC容器底层就是拿到类的全路径,然后根据全路径可以通过反射的技术来创建实例。

IOC容器步骤:

  1. 创建一个spring的配置文件
  2. 对 xml配置文件 进行解析
  3. BeanFactory工厂类
  4. 在工厂类中通过反射创建bean对象

2、Spring的IOC容器介绍

  • spring中,core模块:IOC容器
    在这里插入图片描述
    上图是Spring IOC容器中接口的继承关系。
    ApplicationContextBeanFactory 子接口实现之一;
    BeanFactory是IOC容器定义的最底层的接口
    ApplicationContext 是高级实现之一,对 BeanFactory 的接口做了很多的扩展,大部分情况使用ApplicationContext

ApplicationContext接口常见的实现类

  1. ClassPathXmlApplicationContext
//读取classpath中的资源
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationcontext.xml");
  1. FileSystemXmlApplicationContext
//读取系统指定的资源文件
FileSystemXmlApplicationContext applicationContext1 = new FileSystemXmlApplicationContext("d://test.xml");
  1. XmlWebApplicationContext
//读取web环境下的资源文件
XmlWebApplicationContext applicationcontext = new XmlWebApplicationContext();

Spring IOC容器来获取bean对象的过程
在这里插入图片描述

3、Spring对Bean的实例化方式

spring容器来实例化bean对象主要有两种方式:
基于注解形式 和 基于配置形式。

(1) 基于配置形式

bean的实例化基于配置的方式:

a. 通过无参构造函数实例化
<!--通过无参构造来实例化Bean-->
<bean id="user" class="bean.User" scope="singleton"/>
  • spring容器对上面的类的实例化采用的是无参构造函数来实例化bean。
    注意:
    如果不指定无参构造函数,会生成一个默认的无参构造函数;
    如果指定了有参构造函数,(就不会生成默认的无参构造函数),就必须手动写一个无参构造函数。
b. 通过静态工厂方式实例化
//创建静态工厂类来获取User对象
public class StaticFactory {
    public static User getUser(){
        return new User();
    }
}
  • spring容器管理配置如下:
<!--通过静态工厂类获取User对象-->
<bean id="user1" class="factory.StaticFactory" factory-method="getUser"/>
  • 静态工厂方式获取对象是 class属性指的是工厂类的全路径factory-method 属性指在工厂类中指定的方法来获取需要的对象。
c. 通过普通工厂方式实例化
//创建一个普通工厂来管理user
public class CommonFactory {
    public User getUser(){
        return new User();
    }
}
  • spring容器配置如下:
<!--通过普通工厂类获取User对象-->                                            
<!--先获取工厂实例-->                                                    
<bean id="factory" class="factory.CommonFactory"/>                
<!--指定工厂类的方法-->                                                   
<bean id="user2" factory-bean="factory" factory-method="getUser"/>
  • 首先需要获取工厂实例,通过普通工厂实例获取user对象时,factory-bean 属性指的是容器管理的工厂对象factory-method 属性指的是工厂中获取user对象的方法
(2) 基于注解形式
  • 基于注解形式比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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    <!--开启扫描注解:指定的包路径下的类,会扫描的到类的方法、属性-->
    <context:component-scan base-package="bean"/>

    <!--只扫描类中属性的注解(比较片面化,一般不使用)-->
    <!--<context:annotation-config></context:annotation-config>-->
</beans>
  • 在对应的类上添加注解,这里的注解必须在给定的包路径(这里是bean包)下的类上写,在别的类上写识别不了。
@Component("user")
//注解中user就相当于 XML配置形式中 bean下的 id属性
public class User {
    private Integer id;
    private String name;
}
  • 这里使用的注解是@Component
    @Component通用注解
    @Repository:对DAO层实现类进行标注(和数据库打交道)
    @Service:对 Service层业务逻辑层 进行标注
    @Controller:对 Controller的实现类 进行标注
  • 以上四个注解可以通用,功能一样,可以互换,使用不同注解主要是区分被注解的类处在不同的业务层,使逻辑更加清晰。

4、Spring中依赖注入方式

bean的实例化说明的是IOC的问题,创建对象之后对象中的属性如何赋值问题,即依赖注入问题(DI)。

(1) 基于xml配置实现依赖注入

基于xml配置文件实现依赖注入有两种方式:通过有参构造、通过 setter 方式。

有参构造函数

以user对象为例,User类必须提供有参构造函数:

public class User {
    private Integer id;
    private String name;
    private Book book;
    
    //有参构造函数
    public User(Integer id, String name, Book book) {
        this.id = id;
        this.name = name;
        this.book = book;
    }
}

容器的配置如下:

<!--依赖注入:有参构造函数-->                           
<bean id="user3" class="bean.User">          
    <!--注入属性                                 
        name :给定类的属性名称                       
        value:对指定属性名称赋值 ,直接获取的是String类型的值    
        ref  :对指定属性进行赋值 指定的是一个容器管理的对象        
    -->                                      
    <constructor-arg name="id"  value="1"/>  
    <constructor-arg name="name" value="图论"/>
    <constructor-arg name="book" ref="book"/>
</bean>                                      
  • 通过有参构造函数完成依赖注入时,使用 constructor-arg 标签进行属性赋值。
setter方式

前提:在User类的属性必须具有setter的方法。

public class User {
    private Integer id;
    private String name;
    public User() {
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

容器中的配置信息如下:

<!--依赖注入:setter方式-->                   
<bean id="user4" class="bean.User">    
    <!--属性注入-->                        
    <property name="id" value="2"/>    
    <property name="name" value="基础"/> 
</bean>                                
  • setter方式的依赖注入:使用 property 标签进行赋值,包括自定义类型。自定义类型无论是set方法还是有参构造均可,注意,对自定义类型赋值时使用 ref
<bean id="user3" class="bean.User">
	<constructor-arg name="book" ref="book"/>
</bean>
  • 注入集合类型:数组、Set、List、Map的个形式集合都可以注入。处理集合存在以下标签:
    在这里插入图片描述
    map类型为例,进行介绍
public class User {
    private Integer id;
    private String name;
    private Map<String ,String> map; //map 类型属性
}

容器中的配置:

<!--map集合类型-->                                
<bean id="user5" class="bean.User">           
    <!--属性注入-->                               
    <property name="id" value="3"/>           
    <property name="name" value="基础班"/>       
    <property name="map">                     
        <map >                                
            <entry key="1" value="11"></entry>
            <entry key="2" value="22"></entry>
            <entry key="3" value="33"></entry>
        </map>                                
    </property>                               
</bean>                                                                              
(2) 基于注解形式注入依赖

依赖的注入都是在类的属性上。

  1. @Value :注入普通类型属性,加在类中属性上方。
    在这里插入图片描述
  2. @Resource :注入对象类型,可以根据属性类型注入,也可以根据属性名称注入。
  3. @Autowired :注入对象类型,表示根据属性类型注入。

注解 @Resource@Autowired 的异同点?

  • Spring中,@Resource和@Autowired都是做bean的注入时使用。使用过程中,有时候@Resource 和 @Autowired可以替换使用,有时不可以。
  • 共同点
    @Resource和@Autowired都可以作为注入属性的修饰,在接口仅有单一实现类时,两个注解的修饰效果相同,可以互相替换,不影响使用。
  • 不同点
    @ResourceJava自己的注解,@Resource有两个属性是比较重要的,分是 nametype;Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
    @Autowiredspring的注解,是spring2.5版本引入的,Autowired只根据 type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。如果有多个实现类,类型相同,@Autowired无法进行注释。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值