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

<bean id=“sqlsession” class=“SqlSessionFactoryBuilder”

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 基于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
				//导入的依赖
				<?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
	                        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
可见在获取之前就已经构造初始化了


修改:
<bean id="user" class="com.it.entity.User" lazy-init="true"></bean>

获取前
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 然后引用工厂,用工厂的方法创建bean-->
    <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><!--任何类型都被写成字符串类型,但是如果对应类型写错会编译通不过   例如 int类型的age写成ABC  -->
     <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命名空间进行属性注入

<!--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命名空间注入
<!--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”

步骤二:引入外部配置文件:<context:property-placeholder location=“classpath:db.properties”></context:property-placeholder>

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

<!--第二步引入properties-->
<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>
     <!--sxpression   表达式-->
     <!--获取其他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>vklsdjf</value>
                             <value>vklsdjf</value>
                             <value>vklsdjf</value>
                             <value>vklsdjf</value>
                     </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文件中<context:component-scan base-package=“包,包,包”

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

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(){
	
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值