6.ssm之springIOC

Spring

1 Spring的初步认识

1.1 基本概述

​ Spring是一个设计层面的框架(不属于某一层),用于整合业务和其他层的交互,简化项目的设计和开发。核心是ioc和aop。

  • IOC:inversion of control,控制反转容器,用来整合其他框架。将对象的创建,初始化,分配,使用,维护和销毁等功能交给Spring来进行管理。
    • DI:Dependency Injection,依赖注入,容器知道那个组件运行时需要另一个类,在需要的时候利用反射将组件注入到指定的组件中去。
  • AOP:Aspect Oriented Programming,面向切面编程,主要用于对事务的管理。
    • 面向过程:专注功能的实现。
    • 面向对象:专注于某个对象。
    • 面向切面:专注于所有对象的某个功能。实现核心业务逻辑和辅助功能的分离。
  • 组件的划分:

image-20201029154607481

1.2 项目的搭建

​ 使用的idea的maven项目

1 创建maven项目并配置pom文件

<?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">
    <parent>
        <artifactId>ssm</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>03_spring</artifactId>
    <dependencies>
        <!--导入spring基础五个包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <!--导入单元测试的包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>
</project>

2 创建spring的核心配置文件

<?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">

    <!--1.创建一个javaBean对象,使用property赋值,实际上使用set方法-->
    <bean id="student01" class="com.zhiyou.pojo.Student">
        <property name="sid" value="001"/>
        <property name="sname" value="张三丰" />
        <property name="sex" value="" />
        <property name="score" value="98" />
    </bean>
    <!--2.构造方法进行对象创建并赋值-->
    <bean id="student02" class="com.zhiyou.pojo.Student">
        <constructor-arg name="sid" value="002" index="0" />
        <constructor-arg name="sname" value="尼古拉斯赵六" index="1" />
        <constructor-arg name="score" value="98" index="3"/>
        <constructor-arg name="sex" value="" index="2" />
    </bean>
</beans>

注:配置文件的作用是为了让Spring感知到这些组件的存在。

3 创建测试类进行ioc容器的测试

public class IOCTest {
    ApplicationContext ioc= new ClassPathXmlApplicationContext("spring-config.xml");
    @Test
    public void test01(){
        Object student01 = ioc.getBean("student01");
        System.out.println(student01);
        Object student02 = ioc.getBean("student02");
        System.out.println(student02);
    }
}

结果展示:

image-20201029154814237

2 SpringIOC

2.1 bean的赋值
2.1.1 简单属性的赋值

1 使用property标签

<!--1.创建一个javaBean对象,使用property赋值,实际上使用set方法-->
<bean id="student01" class="com.zhiyou.pojo.Student">
    <property name="sid" value="001"/>
    <property name="sname" value="张三丰" />
    <property name="sex" value="" />
    <property name="score" value="98" />
</bean>

property赋值的方式是使用该类的setter方法来实现的。

2 使用构造器实例化

<!--2.构造方法进行对象创建并赋值-->
<bean id="student02" class="com.zhiyou.pojo.Student">
    <constructor-arg name="sid" value="002" index="0" />
    <constructor-arg name="sname" value="尼古拉斯赵六" index="1" />
    <constructor-arg name="score" value="98" index="3"/>
    <constructor-arg name="sex" value="" index="2" />
</bean>
2.1.2 手动装配

​ 手动装配:如果类中存在其他类对象,可以采用ref引用的方式来引用其他bean来实现注入。

<!--1.创建一个javaBean对象,使用property赋值,实际上使用set方法-->
<bean id="student01" class="com.zhiyou.pojo.Student">
    <property name="sid" value="001"/>
    <property name="sname" value="张三丰" />
    <property name="sex" value="" />
    <property name="score" value="98" />
    <property name="car" ref="car01" />
</bean>
<!--2.构造方法进行对象创建并赋值-->
<bean id="student02" class="com.zhiyou.pojo.Student">
    <constructor-arg name="sid" value="002" index="0" />
    <constructor-arg name="sname" value="尼古拉斯赵六" index="1" />
    <constructor-arg name="score" value="98" index="3"/>
    <constructor-arg name="sex" value="" index="2" />
    <constructor-arg name="car" ref="car01" />
</bean>
<!--3-->
<bean class="com.zhiyou.pojo.Car" id="car01">
    <property name="carName" value="保时捷" />
    <property name="carColor" value="蓝色" />
    <property name="price" value="99.8" />
</bean>

代码测试:

public class IOCTest {
    ApplicationContext ioc= new ClassPathXmlApplicationContext("spring-config.xml");
    @Test
    public void test01(){
        Student student01 = (Student)ioc.getBean("student01");
        System.out.println(student01);
        student01.getCar().setCarName("奔驰--梅萨瑟斯");
        Object student02 = ioc.getBean("student02");
        System.out.println(student02);
    }
}

结果展示

Tim截图20200818145622

多个对象引用获取的到car是同一个对象,如果我们修改了其属性,其他对象获取到的该对象的属性值也会发生变化。

2.1.3 基于Xml的自动装配

自动装配:

  • autowire:“default”:不进行自动装配
  • autowire:“byName”:按照名字来赋值,以属性名为id在容器中寻找这个组件。如果找到且类型匹配就装配,否则为null。相当于getBean(car)
  • autowire:“byType”:按照属性的类型在容器中寻找该类型的组件,
    • 如果找到一个则进行装配。相当于getBean(Car.class)。
    • 如果存在多个该类型的bean,则会报错。
    • 如果找不到,则装配null。
  • autowire:“constructor”:先按照有参构造器的参数类型进行装配。如果没有则装配一个null;如果按照类型存在多个,参数的名作为id继续进行装配,如果有则进行装配,如果没有找到则装配null。
  • autowire:“no”:

如果存在List,在xml中如果存在多个book,我们选择使用byType的时候会将这些bean实例化,并自动赋值给List

代码实现:

<bean class="com.zhiyou.pojo.Car" id="car01">
    <property name="carName" value="保时捷" />
    <property name="carColor" value="蓝色" />
    <property name="price" value="99.8" />
</bean>
<!--自动装配-->
<bean id="student03" class="com.zhiyou.pojo.Student" autowire="byType">
</bean>
<!--手动装配-->
<bean id="student04" class="com.zhiyou.pojo.Student">
    <property name="car" ref="car01" />
</bean>
2.2 bean的作用域
2.2.1 懒加载

​ 默认情况下,当ioc容器初始化的时候会创建bean对象,我们可以通过设置lazy-init="true"来设置bean进行懒加载。

  • 如果为true则表示懒加载,在第一次获取该对象的时候创建对象。
  • 如果是false为非懒加载,容器初始化的时候创建该对象。
<bean id="student04" class="com.zhiyou.pojo.Student" lazy-init="true">
    <property name="car" ref="car01" />
</bean>
2.2.2 通过scope属性设置作用域

​ scope设置bean的作用域存在五个属性。

  • prototype:原型模式。
    • 在容器启动的时候不会创建该类对象,只有在调用的时候才会进行创建。类似于懒加载的效果。
    • 多次获取则是多个对象。
  • singleton:单例模式。默认情况下为该模式。
    • 在容器启动完成之前就已经创建好对象,保存在容器中。
    • 不论在哪里获取,都是同一个对象。
  • request:在web环境下,同一次请求创建一个bean实例
  • session:web的情况下,同一个会话创建一个bean实例
<bean id="car01" class="com.zhiyou.pojo.Car" scope="prototype"></bean>
<bean id="car02" class="com.zhiyou.pojo.Car" scope="singleton"></bean>
2.2.3 bean的生命周期

​ 在对象创建和销毁前后调用指定的方法。

<bean id="buyCar" class="com.zhiyou.pojo.Car" init-method="initMethod" destroy-method="destoryMethod">
    <property name="carName" value="玛莎拉蒂" />
    <property name="price" value="998" />
</bean>
@Test
public void test05(){
    ConfigurableApplicationContext ca=(ConfigurableApplicationContext)ioc;
    ca.close();
}

image-20201029160359330

特点:

  • 如果我们指定懒加载,且是单例bean的情况下,在容器启动的时候就加载这个对象,调用初始化的方法。
  • ioc容器销毁则调用该对象的销毁方法。
  • 如果对象是非单例bean或配置了懒加载,则在获取的时候调用初始化方法。
2.3 复杂类型的赋值
2.3.1 赋值null,外部引用,内部创建
<bean id="person01" class="com.atguigu.bean.Person">
    <!--value赋值都是一些简单的属性,null不在其中-->
    <property name="lastName" value="NULL"></property>
    <!-- 真正的给属性赋予null值的方式-->
    <property name="age"><null/></property>
    <!-- ref代表引入当前已经存在组件,是严格的引用-->
    <!-- <property name="car" ref="car01"></property> -->
    <!--相当于car=new Car();-->
    <property name="car">
        <bean class="com.atguigu.bean.Car">
            <property name="carName" value="自行车"></property>
        </bean>
    </property>
</bean>
2.3.2 为一些复杂的属性进行赋值

​ 为list,map,properties属性进行赋值

<bean id="person02" class="com.atguigu.bean.Person">
    <!--配置list类型的属性-->
    <property name="books">
        <!-- 相当于books=new ArrayList() -->
        <list>
            <!-- p命名空间赋值一本书 -->
            <bean class="com.atguigu.bean.Book" p:bookName="西游记"></bean>
            <!-- 引入外部一个元素 -->
            <ref bean="book01"/>
        </list>
    </property>
    <!--配置map类型的属性-->
    <property name="maps">
		<map>
			<!-- 一个entry就代表是一个键值对 -->
			<entry key="key01" value="张三"></entry>
			<entry key="key02" value="李四"></entry>
			<entry key="key03" value-ref="book01"></entry>
			<entry key="key04">
				<bean class="com.atguigu.bean.Car">
					<property name="carName" value="奔驰"></property>
				</bean>
			</entry>
		</map>
	</property>
    <!--配置properties类型的属性-->
	<property name="properties">
		<!-- properties=new Properties(); key-value都是String类型 -->
		<props>
			<prop key="username">root</prop>
			<prop key="password">19971001</prop>
		</props>
	</property>
</bean>

代码测试:

@Test
	public void test04() {
		//ApplicationContext:代表ioc容器
		//ClassPathXmlApplicationContext:代表当前应用的xml配置文件在ClassPath下
		ApplicationContext ioc=new ClassPathXmlApplicationContext("ioc2.xml");
		//获取容器帮我们创建好的对象
		Person person=(Person)ioc.getBean("person02");
		System.out.println("list=====");
		List<Book> books = person.getBooks();
		for (int i = 0; i < books.size(); i++) {
			System.out.println(books.get(i));
		}
		System.out.println("map=====");
		Map<String, Object> maps = person.getMaps();
		Iterator<Entry<String, Object>> iterator = maps.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, Object> next = iterator.next();
			System.out.println(next.getKey()+"==="+next.getValue());	
	}
	System.out.println("propertis=====");
	Properties properties = person.getProperties();
	System.out.println(properties);
}

image-20201029160506732

注意:内部bean不能被其他bean组件获取到,只能内部自己使用。

3 util名称空间创建集合类型的bean

  • 导入util命名空间
  • 在xml中配置相应的集合属性
<bean class="com.atguigu.bean.Person" id="person03">
	<!-- 此时需要引用其他bean的map属性,使用util -->
	<property name="maps" ref="mymap">
	</property>
</bean>
<!-- 相当于new LinkedHashMap -->
<util:map id="mymap">
	<!-- 一个entry就代表是一个键值对 -->
    <entry key="key01" value="张三"></entry>
    <entry key="key02" value="李四"></entry>
    <entry key="key03" value-ref="book01"></entry>
    <entry key="key04">
    <bean class="com.atguigu.bean.Car">
    	<property name="carName" value="奔驰"></property>
    </bean>
    </entry>
</util:map>

优点:

  1. 存在id可以被其他bean复用。

  2. 可以直接根据ioc容器根据id来进行获取

2.4 工厂模式初始化对象

​ bean的创建默认是框架利用反射new出来的bean实例。工厂模式:工厂帮我们创建对象,有一个专门帮我们创建对象的类,这个类就是工厂。配置通过静态工厂方法创建的bean,实例工厂方法创建的bean,FactoryBean。

​ AirPlane ap=AirPlaneFactory.getAirPlane(String jzName);

​ 静态工厂:工厂本身不需要创建对象;通过静态方法的调用,对象=工厂类.工厂方法名();

​ 实例工厂:工厂本身创建对象;需要先创建一个工厂类的对象。

​ 工厂类 工厂对象=new 工厂类();

​ 工厂对象.getAirPlane(“张三”);

2.4.1 静态工厂
<!-- 1.静态工厂(不需要创建工厂本身)factory-method="getAirPlane" 指定那个方法是工厂方法。容器启动就创建
   class:指定静态工厂的全类名
   factory-method:指定工厂方法
   constructor-arg:可以为方法传参。
  -->
<bean id="airPlaneFactory" class="com.atguigu.factory.AirPlaneStaticFactory" factory-method="getAriPlane">
    <constructor-arg name="jzName" value="张三"></constructor-arg>
</bean>
2.4.2 实例工厂
<!-- 2.实例工厂的工厂方法、容器启动就创建
	 		先创建实例工厂对象。
	 		创建AirPlane对象。
	 			factory-bean:指定工厂bean
	 			factory-method:	指定工厂方法
-->
<bean id="airPlaneFactory2" class="com.atguigu.factory.AirPlaneInstanceFactory">
</bean>
<bean id="airplane02" class="com.atguigu.bean.AirPlane" factory-bean="airPlaneFactory2" factory-method="getAriPlane">
    <constructor-arg name="jzName" value="李四"></constructor-arg>
</bean>
2.4.3 实现FactoryBean接口

需要实现的方法

  • getObject():spring调用,创建对象的。
  • getObjectType():spring调用,返回类的类型
  • isSingleton():是否是单例

使用:

  • 创建类实现接口
  • ioc容器中进行组件注册
<!-- FactoryBean:是Spring规定的一个接口,只要是这个接口的实现类,Spring都认为是一个工厂
    实现创建对象的实际和单多实例没有关系,都是在创建实例的时候创建的。	
   -->
<bean id="myFactoryBeanImpl" class="com.atguigu.factory.MyFactoryBeanImpl"></bean>
2.5 注解的形式注册组件

​ 分别创建Dao,Service,Controller

1 注解方式配置组件

<!-- 使用注解创建DAO,Service,Controller
		通过给bean添加某些注解,可以快速的将bean加入到ioc容器中
		存在四个注解:某个类上添加上任何一个注解,都可以将这个bean添加到ioc容器中
			@Controller:推荐给控制器层组件添加这个注解。
			@Service:推荐给业务逻辑层的组件添加这个注解。
			@Repository:推荐给dao层的组件添加这个注解。
			@Component:组件,给不属于以上几层的组件添加这个注解,ioc容器启动的时候就加载。
		注意:Spring底层不会验证这个组件,我们推荐加各自的注解,是给我们自己看的。
		注解方式:将组件加入到容器中去
			1)给要添加的组件上添加注解
			2)配置ioc自动扫描添加注解的组件,
				导入context命名空间.
				配置组件:component-scan
			3)一定要导入aop包,支持添加注解模式的。
	 -->
	 <!-- base-package:扫描的基础包,会扫描该包即子包的所有加了注解的类。自动的扫描进ioc容器中
	 		注意:最好稍微精确一些。否则可能将lib下的类也扫描到。
		 	Caused by: java.lang.ClassNotFoundException: org.springframework.aop.TargetSource
		 	使用配置和注解的方式扫描进ioc容器的行为默认都是一致的。
		 		1)组件的id为类名首字母小写。
		 			@Controller("bookServletTest"):此方式可以修改组件的id。
		 		2)组件默认是单例的.
		 			通过使用新的注解@Scope(value="prototype"):可以将该组件调整为多实例的
	  -->
	 <context:component-scan base-package="com.atguigu"></context:component-scan>

image-20201029160851578

**思考:**为什么存在注解,还要学习配置bean的方式?

​ 因为注解的方式仅仅适用于自己写的类,如果想要配置jar包中类,使用注解的方式是不现实的,因此我们可以使用配置bean的方式来实现。

2 排除哪些指定的组件

<context:component-scan base-package="com.atguigu">
    <!-- context:exclude-filter指定扫描包时候不包含的类
     排除一些不需要的组件。
    type="annotation":指定排除的规则,按照注解进行排除,标注了指定注解的组件就不需要。
     expression="org.springframework.stereotype.Controller":注解的全类名。
    type="assignable":指定排除某个具体类。按照类进行排除.
     -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <context:exclude-filter type="assignable" expression="com.atguigu.service.BookService"/>
</context:component-scan>

image-20201029161125688

3 只要哪些组件

<context:component-scan base-package="com.atguigu" use-default-filters="false">
	<!-- context:include-filter指定扫描包时候包含的类
		 只扫描哪些组件,默认全部扫描进来。
	-->
	<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

注意:需要关闭默认的过滤器。

image-20201029161147821

2.6 使用@Autowired实现DI

1 使用方式

​ 在需要自动注入的属性上面添加该注解即可。

image-20201029161309869

2 @Autowired原理:

  • 先按照类型去容器中寻找相应的组件:bookSerice=ioc.getBean(BookService.class)。
    • 如果找到一个就赋值;
    • 如果没找到就抛出异常;
    • 如果找到多个。就根据变量名为id继续在容器中进行寻找。
      • 如果找到则进行装配。
      • 如果没有找到则进行报错。

@Qualifier(“名称”):指定一个名称作为一个id。让Spring不使用变量名称作为id。如果依旧没找到,则会接着进行报错。

可以在AutoWired(“required=false”)设置如果找不到就装配null。

注意:任何情况下,Autowired标注的自动装配的属性都必须找到,否则会报错。

3 Autowired可以装配的位置

image-20201029161337975

如果装配到方法上面:

  • 这个方法回在bean创建的时候自动运行。
  • 这个方法上的每一个参数都会自动注入值。

4 @Qualifier可以装配的位置

image-20201029161406732

可以实现自动装配的注解:Autowired,Resource,Inject

5 Autowired和Resource的区别?

  • @Autowired:最强大,是Spring自己的注解,@Resource:是j2ee,java的标准。
    果找到一个就赋值;
    • 如果没找到就抛出异常;
    • 如果找到多个。就根据变量名为id继续在容器中进行寻找。
      • 如果找到则进行装配。
      • 如果没有找到则进行报错。

@Qualifier(“名称”):指定一个名称作为一个id。让Spring不使用变量名称作为id。如果依旧没找到,则会接着进行报错。

可以在AutoWired(“required=false”)设置如果找不到就装配null。

注意:任何情况下,Autowired标注的自动装配的属性都必须找到,否则会报错。

3 Autowired可以装配的位置

[外链图片转存中…(img-LaXSrUe2-1603959314281)]

如果装配到方法上面:

  • 这个方法回在bean创建的时候自动运行。
  • 这个方法上的每一个参数都会自动注入值。

4 @Qualifier可以装配的位置

[外链图片转存中…(img-kkb5s53X-1603959314283)]

可以实现自动装配的注解:Autowired,Resource,Inject

5 Autowired和Resource的区别?

  • @Autowired:最强大,是Spring自己的注解,@Resource:是j2ee,java的标准。
  • @Resource是标准,是java的标准,扩展性更强;@Autowired是Spring自己的标准,只支持自己家的标准。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值