spring框架IOC和DI详解

spring框架介绍以及核心功能IOC DI

一.spring框架介绍

  1. spring是什么?

一。spring本身是一个轻量级框架集合

二。spring是一个企业级一站式的框架(spring boot, spring data,spring framework spring mvc)

三。spring又有很好的包容性,他为所有知名框架编写兼容jar,而且spring做很多杂活,例如兑现管理,事务管理,日志输出等,因此spring变得不可或缺

四。spring不排斥其他框架,与其他框架完美融合

ssh : spring struts hibernate

ssm: spring spring mvc mybaties

  1. spring有什么用

创建对象

1方便解耦 spring是一个对象工厂,内部可以帮助创建对象,以及对象的管理

例如:dbutils 工具类queryrunner = new queryrunner();

和hibernate 持久层框架:

​ SqlsessionFactoryBuilder

​ SqlsessionFactory

​ SqlSession

​ SqlSession.crud

spring 帮我们创建这些复杂的对象创建过程

spring-hiberbnate来创建对象

application.xml

resource=“hibernate.xml”>

@Resource

SqlSession sqlsession;

spring 大工厂通用的创建对象模板

管理对象

例如:

class A

​ B b;

class B;

​ A a;

#### 特点
支持事务 spring-tx
方便集成各种框架 hibernate、mybatis、struts等
对aop技术的支持 spring-aop,spring-aspects aopalliance aspectjweaver…
支持其他优秀框架
spring框架的组成

spring framework组成部分

spring web 控制器以及spring mvc

spring dao 持久层和事务

spring aop 面向切面

spring core container 核心IOC DI

spring test 测试

spring框架IOC和DI详解_第1张图片

二.spring框架核心功能之IOC 基于XML文件配置

什么是IOC

	```java
			ioc  inversion of control 控制反转
	
			将java对象的创建权利交给spring处理   有效解耦在配置文件中写bean名字,犬类路径名等。为反射提供环境,用无参构造创对象
	
	#### 体验IOC 
	
	​		目的:将一个类的对象创建权利叫给spring
	
	1. 步骤一:
	
	   导入spring的jar包:beans    core   context  expression
	
	2. 步骤二:
	
	   创建配置文件applicationContext.xml
	3:配置文件编写 applicationContext.xml
				//导入的依赖
				
	                <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
	                        https://www.springframework.org/schema/beans/spring-beans.xsd">
	                       
	                    <bean id="user" class="com.it.entity.User">bean>
	    				<bean id="person" class="com.it.entity.Persion" scope="prototype">bean>
	                beans>
	
	4:. 步骤三:编写实体类,测试代码
	
				//第一步获取容器
	        ApplicationContext context =
	                new ClassPathXmlApplicationContext("applicationContext.xml");
	        //第二步单例获取bean
	        Object user = context.getBean("user");
	        System.out.println(user)//com.it.entity.User@7ed7259e
	

三,详解配置文件的IOC

标签的使用

  1. name:为bean的名字。名字中可以有特殊符号,但是不可以有空格。
  2. id:为bean的名字,名字可以有特殊符号,包括空格

name和id的异同

相同点:

  1. 多个bean之间的id、name必须唯一
  2. 为bean起名时都可以包含特殊符号
  3. id 和bean不可以重名

不同点:

  1. id可以包含空格,name不可以有空格

区别测试:

<bean name="user^^^" class="com.it.entity.User">bean>
    <bean id="user##" class="com.it.entity.User">bean>
Object user = context.getBean("user^^^");
        Object bean = context.getBean("user##");
        System.out.println("user = " + user);
        System.out.println("bean = " + bean);
result:
user = com.it.entity.User@7fa98a66
bean = com.it.entity.User@15ff3e9e
<bean name="user  ^^^" class="com.it.entity.User">bean>
    <bean id="user  ##" class="com.it.entity.User">bean>
//Object user = context.getBean("user  ^^^");
        Object bean = context.getBean("user  ##");
        //System.out.println("user = " + user);
        System.out.println("bean = " + bean);
result:
bean = com.it.entity.User@7fa98a66
Object user = context.getBean("user  ^^^");
        //Object bean = context.getBean("user  ##");
        System.out.println("user = " + user);
        //System.out.println("bean = " + bean);
result:
NoSuchBeanDefinitionException: No bean named 'user  ^^^' available

  1. class:bean 的全类路径名,spring拿到通过反射来用无参构造创建对象 而且只用无参构造创建对象

测试无参创建对象:覆盖无参构造

/*public User() {
    }*/

    public User(int age, String name, String gender) {
        this.age = age;
        this.name = name;
        this.gender = gender;
    }
<bean id="user" class="com.it.entity.User"></bean>//此处报红,显示no such
    constructor method
  1. scope:

    1. singleton:单例

    默认测试:

    Object user = context.getBean("user");Object user1 = context.getBean("user");System.out.println(user);System.out.println(user1);
    com.it.entity.User@7fa98a66
    com.it.entity.User@7fa98a66
        相同:证明多次获取的同一个bean
    
    1. prototype 多例

    多例测试:

    <bean id="user" class="com.it.entity.User" scope="prototype"></bean>
    
     Object user = context.getBean("user");
            Object user1 = context.getBean("user");
            System.out.println(user);
            System.out.println(user1);
            
            com.it.entity.User@7334aada
    com.it.entity.User@1d9b7cce
    不一样:说明多次获取不同的bean
    
  2. lazy-init:

默认测试:

System.out.println("获取前");
        Object user = context.getBean("user");
        System.out.println(user);
        
constructor----------
获取前
com.it.entity.User@7fa98a66
可见在获取之前就已经构造初始化了


修改:


获取前
constructor----------
com.it.entity.User@62150f9e
可见:在获取后才构造初始化的

多例模式下:始终是懒加载
  1. init-method 和destroy-method:
//    初始化方法
    public void init(){
        System.out.println("User.init");
    }
    //销毁方法
    public void destrory(){
        System.out.println("User.destrory");
    }
constructor----------
User.init
获取前
com.it.entity.User@7fa98a66
初始化方法在构造器之后执行
销毁方法没有执行
关闭容器:发现销毁方法执行了
钩盖成多利模式:发现无论关闭容器与否,都不执行销毁方法

四 springIOC容器

1:获取容器传入配置文件

spring ioc包含在spring-context中

ioc容器的总接口 ApplicationContext

因此需要借助实现类才可以获取容器

  1. FileSystemXmlApplicationContext 磁盘绝对路径
  2. ClassPathXmlApplicationContext 项目相对路径寻找配置文件

注意:

  1. 在编译后查看文件是否被加载进target里面
  2. 检查配置文件名字是否正确

2:获取Bean

容器名.getBean(String name) Object

容器名.getBean(String name,aClass); Entity

3:静态工厂

​ 对象是通过工厂模式创建出来的

public ststic User createUser(){
	return new User("uuu",11);
}

 <bean id="user2" class="com.it.entity.UserFactory" factory-method="createUser">bean>

result:

argument constructor 333333
argument constructor 333333
User{name=‘hfh’, age=12}
User{name=‘uuu’, age=11}

4:非静态工厂模式

创建对象的方式是非静态的

创建非静态工厂

创建对象


    <bean id="factory" class="com.it.entity.UserFactory">bean>
    <bean id="user3" factory-bean="factory" factory-method="createUser">bean>

result:

argument constructor 333333
User{name=‘uuu’, age=11}

注意 :在配置文件中只要写了完整的创建bean的配置,构造器就会执行,即使你不在业务代码中调用它

五 注入 Di

回顾:spring使用xml进行ioc 控制反转 使用spring进行对象创建和管理

spring是一个大工厂,可以帮我们创建对象和管理

spring xml 格式的DI有两个核心前提

1:如果spring IOC 容器的对象需要DI的另一个对象,要求他们都应该被IOC管理

2:xml 进行对象的DI 时候要求对象必须要设置属性的getter|setter方法

1. 基本注入

基本类型|值类型的属性 name value 形式

<bean id="person" class="com.it.entity.Person">
     <constructor-arg name="age" value="12">constructor-arg>
     <constructor-arg name="name" value="何发海">constructor-arg>
 bean>引用类型

2.引用类型 name ref 要求:ref的值应该由容器管理


 <bean id="person" class="com.it.entity.Person">
     <constructor-arg name="age" value="12">constructor-arg>
     <constructor-arg name="name" value="何发海">constructor-arg>
     <constructor-arg name="doctor" ref="doctor1">constructor-arg>
 bean>
 
 <bean id="doctor1" class="com.it.entity.Doctor">
     <constructor-arg name="age" value="12">constructor-arg>
     <constructor-arg name="username" value="jklh">constructor-arg>
 bean>
 
 <bean id="person1" class="com.it.entity.Person">
     <property name="age" value="12">property>
     <property name="name" value="hfh">property>
     <property name="doctor" ref="doctor">property>
 bean>
 <bean id="doctor" class="com.it.entity.Doctor">
     <property name="age" value="43547">property>
     <property name="username" value="bbbb">property>
 bean>

注意:基本类型或者值类型使用value赋值

引用类型使用ref引用已经存在的IOC对象id名

案例:

有一学生类:姓名、性别、地址对象、学校对象

地质类:省 市 县 使用构造函数赋值

学校类: 学校名 学校占地面积 学生人数

打印学生对象打印全信息

<bean id="student" class="com.it.entity.Student">
     <property name="age" value="12">property>
     <property name="address" ref="address">property>
     <property name="school" ref="school">property>
     <property name="sname" value="珍君">property>
 bean>
 <bean id="address" class="com.it.entity.Address">
     <constructor-arg name="city" value="北京">constructor-arg>
     <constructor-arg name="coiuntry" value="昌平">constructor-arg>
     <constructor-arg name="province" value="河北">constructor-arg>
 bean>
 <bean id="school" class="com.it.entity.School">
     <constructor-arg name="area" value="123">constructor-arg>
     <constructor-arg name="cName" value="中国民用航空飞行学院">constructor-arg>
     <constructor-arg name="count" value="120000">constructor-arg>
 bean>

容器三级缓存:先ref引用 后再创建Bean 先解析到bean 后赋值

p命名空间注入

  1. 简单属性注入

步骤一:引入p命名空间约束

xmlns:p="xmlns:p=“http://www.springframework.org/schema/p”"

步骤二:在bean标签内部属性的位置引入p命名空间进行属性注入


 <bean id="student" class="com.it.entity.Student" p:age="55" p:sname="珍君" p:address-ref="address"
 p:school-ref="school">

 bean>
 <bean id="address" class="com.it.entity.Address" p:city="上海" p:coiuntry="昌平" p:province="宁夏">

 bean>
 

构造器简单c命名空间注入


<bean id="school" class="com.it.entity.School" c:area="12345" c:cName="中国民用航空飞行学院" c:count="123456">

bean>

引入外部配置文件注入(properties配置文件)

​ 有时候我们需要在外部定义一些properties文件配置,需要引入到springIOC容器中

步骤一:添加context命名空间:xmlns:context=“http://www.springframework.org/schema/context”

步骤二:引入外部配置文件:

步骤三 在bean标签的value属性中用属性value=${properties里的key}


<context:property-placeholder location="classpath:db.properties">context:property-placeholder>
<bean id="jdbc" class="com.it.entity.Jdbc">
  <property name="password" value="${password}">property>
  <property name="url" value="${url}">property>
  <property name="username" value="${username}">property>
bean>

问题: 一个springioc的xml配置中,可能会引入多个专项properties配置文件!
默认情况只有第一个生效!

解决:
既然框架的设计者在设计约束的时候!允许出现多个property标签,就证明
可以次可以导入多个标签!
只不过默认只支持第一个!

解决方案1:
在每个标签内部添加 ignore-unresolvable=“true”

    	    解决方案2:
    	    location值的时候!使用,进行分开引入!
    	    location="classpath:jdbc.properties,classpath:boot.properties"

classpath和classpath*:的区别classpath会引入resources再有目录的文件 classpath只会引入resources里面的文件

注意 :properties里面只能申明字符串类型,基本类型

spring boot yaml 里面可以申明数组集合 和map

spring expression表达式的注入

​ #{}

1:获取其他bean 的属性值 id名.属性名

<bean id="user" class="com.it.domain.User">
             <property name="name" value="${url}">property>
             <property name="age" value="${aaa}">property>
     bean>
     
     
     <bean id="user2" class="com.it.domain.User">
             <property name="age" value="#{user.age}">property>
             <property name="name" value="#{user.name}">property>
     bean>

2:引入其他bean的函数 id名.函数名字


     <bean id="user3" class="com.it.domain.User">
             <property name="name" value="#{user.getAge()}">property>
     bean>

3:引入java内置函数#{T(内置函数名).函数方法()}


     <bean id="user4" class="com.it.domain.User">
             <property name="age" value="#{T(Math).round(T(Math).random()*100)}">property>
     bean>

4:基本+ - * / % 运算

<bean id="user5" class="com.it.domain.User">
             <property name="name" value="#{'${aaa}'+789}">property>
     bean>

5:复杂类型数据属性的注入

<bean id="car" class="com.it.domain.Car">
             
             <property name="color">
                     <array>
                             <value>白色value>
                             <value>黄色value>
                             <value>黑色value>
                             <value>橘色value>
                             <value>咖啡色value>
                     array>
             property>
             
             <property name="names">
                     <list>
                             <value>vklsdjfvalue>
                             <value>vklsdjfvalue>
                             <value>vklsdjfvalue>
                             <value>vklsdjfvalue>
                     list>
             property>
             <property name="map">
                     <map>
                             <entry key="fsd" value="57525">entry>
                             <entry key="gf" value="fsbvsffd">entry>
                             <entry key="fsd" value="8278">entry>
                             <entry key="fsd" value="27">entry>
                     map>
             property>
     bean>

六注解形式的IOC DI

注解的优势

  1. 注解更加简单方便
  2. 可以进行批量操作,扫描,以包为单位
  3. 注解在进行属性注入时不需要有getter setter 方法

使用场景

  1. 注解通常在自定义的类上使用
  2. xml配置通常配置第三方类

三个基本注解

@Repository

@Controller

@Service

注明value=“类名首字母小写” bean让扫描扫描到此处利用反射创建对象

@PropertySource(“classpath:info.properties”) //引入外部配置文件

@Value(key=“值”)

@Value("${gvdsf}") $ 引入值 “#{}” expresson表达式引入值注入

@Autowired()//自动装配

@Reource(name=“jbkfl”)//区分同名

spring IOC 的使用

使用注解形式的ioc操作需要在类上添加特殊的注解,以及注解需要被扫描

步骤一:类上面加上注解@Component(在ioc中的id值如果不写就会默认类名第一个字母小写)==创对象

步骤二:指定生成的模式@Scope(scopeName=“singleTon”|propotype)

步骤三:扫描在xml文件中

注意:包名越精确越好,效率越高

spring DI

2. 基本类型注入(基本数据类型|值类型|)

@Value() 注入 @PropertySource("")引入外部配置

3. 引用类型注入

@Autowirred() 在变量上面 可根据变量类型查找

如果变量是接口,找到接口早ioc中的实现类对象

问题 如果有多个相同类型他们怎么找

expected single matching bean but found 2: serviceImpl1,serviceImpl2
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:176)

方案:

指定具体的实现类

@Autowired

@Qualifier(“实现类名字”)

方案二:

@Reource(name=“实现类名字”)

注意:如果出现no bean named ‘xxx’ available

  1. 名字写错
  2. 没加注解
  3. 没有扫描

七 spring使用配置类的形式进行配置

spring4以后提供一种配置类的形式进行类替代xml配置文件

步骤一:申明一个配置类

@Configeration   //将一个类变成配置类   替代xml文件
@ComponentScan("com.it")    //扫描
public class Configer{

}

步骤二 初始化容器

ApplicationContext context = new AnnotationConfigApplicationContext(配置类.class);

八spring使用test功能搭建测试环境

junit

spring-test

主要功能视同spring去加载配置文件,不需要自己动手去常见内容进行文件的加载,因为

我们使用注解不需要自己获取容器中的bean

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")//告诉spring去初始化指定的配置文件
public class TestA{
	@Autowired
	private User user;
	@Test
	public void test(){
	
	}
}

你可能感兴趣的:(spring)