初始Spring
Spring
一、什么是Spring?
pring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为J2EE应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。
特点
(1)轻量级:轻量级是针对重量级容器(EJB)来说的,Spring的核心包就不到1M大小,而使用Spring的核心包所需的资源也很小,所以可以在小型设备中使用。
(2)非入侵式:Spring目标是一个非入侵式的服务框架。原因是所有框架都是提供大量的功能供用户去使用,从而简化开发时间和成本,但由于大量的使用了框架的API,使应用程序和框架发生了大量的依赖性,无法从框架中独立出来,更加无法使程序组件在其他程序中使用。
(3)容器:Spring提供了容器功能,容器可以管理对象的生命周期、对象与对象间的关系、我们可以通过编写XML来设置对象关系和初始值,这样容器在启动之后,所有的对象都直接可以使用,不用编写任何编码来产生对象。Spring有两种不同的容器:Bean工厂以及应用上下文
优势
- spring是最大的工厂
- spring负责业务逻辑组件的框架和生成, 并管理业务逻辑组件的生命周期
- spring可以生产所有实例, 从控制器、 业务逻辑组件、 持久层组件
什么是耦合?
-
耦合是指程序间的
依赖关系
- 它包括 :
- 类之间的依赖、方法之间的依赖
-
解耦
: - 降低程序之间的依赖关系
- 实际开发中:
-
编译器不依赖、运行时才依赖
.
- 对象之间的耦合度过高将会出现牵一发而动全身的情况,降低耦合度是软件工程中的目标之一
- IOC的目标是降低各个对象之间的耦合度
- 各个对象之间的耦合关系
模块划分
Spring的核心是控制反转(IoC)和面向切面(AOP)。
1.核心模块Core Container)
Spring的核心模块实现了IOC的功能,它将类与类之间的依赖代码中脱离,用配置的方法进行依模块赖描述,由IOC容器负责类的创建管理获取等。BeanFactory
Context模块构建与核心模块之上,扩展了BeanFactory的功能,包括国际化,资源加载,邮件服务,任务调度等多项功能。ApplicationContext是Context模块的核心接口
表达式语言(Expression Langguage)是统一表达式语言EL的一个扩展,支持设置和获取对象属性,调用对象方法,操作数组,集合等。使用它可以很方便地通过表达式Spring IOC容器进行交互
2.AOP模块
Spring AOP模块提供了满足AOP Alliance规范的实现,还整合了AspectJ这种AOP语言级的框架。通过AOP能降低耦合。
3.数据访问集成模块(Data Access/Integration )
数据访问集成模块 | |
---|---|
JDBC | 提供一个JBDC模板,使用模板能消除冗长的JDBC编码和必须的事务控制,而且能享受到Spring管理事务的好处。 |
ORM | 提供与流行的“对象-关系”映射框架的无缝集成,包括hibernate、JPA、MyBatis等。而且可以使用Spring事务管理,无需额外控制事务。 |
OXM | 提供了一个对Object/XML映射实现,将Java对象映射成XML数据,或者将XML数据映射成java对象,Object/XML映射实现包括JAXB、Castor、XMLBeans和XStream |
JMS | 用于JMS(Java Messaging Service),提供一套 “消息生产者、消息消费者”模板用于更加简单的使用JMS,JMS用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。 |
事务管理 | 该模块用于Spring管理事务,只要是Spring管理对象都能得到Spring管理事务的好处,无需在代码中进行事务控制了,而且支持编程和声明性的事务管理。 |
4、Web模块
- 建立在ApplicationContext模块之上
- 提供了Web应用的功能(文件上传、FreeMarker等。)
- Spring可以整合Struts2等MVC框架.
- Spring自己提供了MVC框架Spring MVC。
5、测试模块
Spring可以用非容器依赖的编程方式进行几乎所有的测试工作,支持JUnit和TestNG等测试框架。
二、初识Spring的IoC容器
1.概念
IoC(控制反转:Inverse of Control)是Spring容器的核心,但是IoC这个概念却比较晦涩,让人不太容易望文生义
2.IoC控制反转和DI依赖注入
传统程序 | IOC |
---|---|
需要主动new一个对象,才能调用方法 | 将创建的对象交给IOC容器,由IOC容器帮忙创建以及注入依赖对象,程序被动的接受IoC容器创建的对象(控制反转) |
直接操作 | IoC确实不够开门见山,所以提出了DI(依赖注入:Dependency Injection)的概念, |
DI(依赖注入:Dependency Injection)
:即让第三方来实现注入,以移除我们类与需要使用的类之间的依赖关系。
目的:IoC是目的,DI是手段,创建对象的过程往往意味着依赖的注入。我们为了实现IoC,让生成对象的方式由传统方式(new)反转过来,需要创建相关对象时由IoC容器帮我们注入(DI)。
简单的说,就是我们类里需要另一个类,只需要让Spring帮我们创建 ,这叫做控制反转;然后Spring帮我们将需要的对象设置到我们的类中,这叫做依赖注入。
IoC和DI的区别?
IoC:控制反转,指将对象的创建权,反转到spring容器。
DI:依赖注入,指在创建对象的过程中,将对象依赖的属性通过配置进行注入。DI的实现依赖于IoC,是IOC中的一种具体实现,先有控制反转才有依赖注入
属性注入的三种方式
使用set方法进行注入
CellPhone类
package com.openlab.pojo;
//注解包 --我用的maven导入的 idea插件里也可以下载
import lombok.*;
//lombok 注解 相当于帮你写了Set方法
@Setter
@ToString
public class CellPhone {
/**
*
* @ClassName: CellPhone
* @Description:
* @author: 奋斗小新人
* @date: 2021年9月13日 18点37分
*/
//创建属性
private String color;
private String phone;
}
beans.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">
<!-- 一、set方法注入属性-->
<!-- 1、配置对象的创建-->
<bean id="cellphone" class="com.openlab.pojo.CellPhone">
<!-- 2、使用property完成属性注入
name:类里面的属性名称
value:向属性中注入的值
-->
<property name="color" value="白色"></property>
<!-- 向属性注入null值-->
<!--<property name="color" >
<null/>
</property>-->
<!--属性值包含特殊符号
1.把<>进行转义
2.把带特殊符号的内容写到CDATA
-->
<!-- <property name="phone" value="<<电话>>"></property> -->
<!-- 用XML文件的特性注入 -->
<property name="phone">
<value><![CDATA[<<电话>>]]></value>
</property>
</bean>
</beans>
测试类
package com.openlab.test;
import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
CellPhone cellphone = context.getBean("cellphone", CellPhone.class);
System.out.println(cellphone.toString());
}
}
测试结果
使用有参构造函数进行注入
CellPhone类
package com.openlab.pojo;
import lombok.*;
//lombok 注解
@ToString
@RequiredArgsConstructor
@AllArgsConstructor
//@NoArgsConstructor 无参构造器注释
//部分参数构造器、全参构造器、
public class CellPhone {
/**
*
* @ClassName: CellPhone
* @Description:
* @author: 奋斗小新人
* @date: 2021年9月13日 18点58分
*/
//创建属性
private String color;
private String phone;
}
beans.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">
<!--二、有参构造注入属性-->
<bean id="cellphone" class="com.openlab.pojo.CellPhone">
<constructor-arg name="color" value="黑色"/>
<constructor-arg name="phone" value="电话" />
</bean>
</beans>
测试类
package com.openlab.test;
import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
CellPhone cellphone = context.getBean("cellphone", CellPhone.class);
System.out.println(cellphone.toString());
}
}
测试结果
使用p名称空间注入
第一步
:添加p名称空间xmlns:p=“http://www.springframework.org/schema/p”。
第二步
:进行属性注入,在bean标签里。
CellPhone类
package com.openlab.pojo;
import lombok.*;
//lombok 注解
@ToString
@Setter
public class CellPhone {
/**
*
* @ClassName: CellPhone
* @Description:
* @author: 奋斗小新人
* @date: 2021年9月13日 19点25分
*/
//创建属性
private String color;
private String phone;
}
beans.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--三、p名称空间注入属性-->
<bean id="cellphone" class="com.openlab.pojo.CellPhone" p:color="颜色" p:phone="电话" />
</beans>
测试类
package com.openlab.test;
import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
CellPhone cellphone = context.getBean("cellphone", CellPhone.class);
System.out.println(cellphone.toString());
}
}
测试结果
Spring对象集合属性注入
CellPhone类
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
//lombok 注解
@Getter
@Setter
@ToString
@NoArgsConstructor
public class CellPhone {
/**
*
* @ClassName: CellPhone
* @Description:
* @author: 奋斗小新人
* @date: 2021年9月13日 19点52分
*/
//创建属性
private String[] names=new String[3];
private List<String> listData;
private Set<String> setData;
private Map<String,Object> mapData;
private Properties propsData;
}
beansdata.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">
<bean class="com.openlab.pojo.CellPhone" name="cellphone">
<property name="arrdata">
<array>
<value>这是数组</value>
<value>白色手机</value>
<value>灰色手机</value>
</array>
</property>
<property name="listData">
<list>
<value>这是列表</value>
<value>中国手机</value>
<value>外国手机</value>
</list>
</property>
<property name="setData">
<set>
<value>这是集合</value>
<value>智能手机</value>
<value>按键手机</value>
</set>
</property>
<property name="mapData">
<map>
<entry key="1" value="map键值对用的entry"/>
<entry key="2" value="小米"/>
<entry key="3" value="华为"/>
</map>
</property>
<property name="propsData">
<props>
<prop key="1">key为1的属性为张三</prop>
<prop key="2">李四</prop>
<prop key="3">王五</prop>
</props>
</property>
</bean>
</beans>
测试类
package com.openlab.test;
import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class TestData {
public static void main(String[] args) {
ApplicationContext factory=new ClassPathXmlApplicationContext("beansdata.xml");
//通过getBean()获取到beansdata.xml文件中Bean对象
CellPhone ce=factory.getBean("cellphone", CellPhone.class);
System.out.println("---数组---");
//遍历数组
for (String str:ce.getArrdata()){
System.out.println(str);
}
System.out.println("---list---");
for (String str:ce.getListData()){
System.out.println(str);
}
System.out.println("---set---");
for (String str:ce.getSetData()){
System.out.println(str);
}
System.out.println("---map---");
//拿到所有的key
Set<String> set=ce.getMapData().keySet();
for (String str:set){
System.out.println(str+"--"+ce.getMapData().get(str));
}
System.out.println("*********通过Propertis取出数据(通过Entry对象取)******");
Properties pp=ce.getPropsData();
for (Map.Entry<Object,Object> entry:pp.entrySet()){
System.out.println(entry.getKey().toString()+"---"+entry.getValue().toString());
}
System.out.println("*********通过Propertis取出数据(通过Enumeration对象取)******");
Enumeration<Object> en = ce.getPropsData().keys();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = ce.getPropsData().getProperty(key);
System.out.println(key + "---" + value);
}
}
}
结果
3.Spring管理bean的作用域
第一种:(默认)
单例模式
CellPhone 类
package com.openlab.pojo;
import lombok.*;
//lombok 注解
@Getter
@Setter
@ToString
@NoArgsConstructor
public class CellPhone {
/**
*
* @ClassName: CellPhone
* @Description:
* @author: 奋斗小新人
* @date: 2021年9月13日 20点34分
*/
//创建属性
private String name;
private Integer price;
}
beansdata.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">
<bean class="com.openlab.pojo.CellPhone" name="cellphone" >
<property name="name" value="小米" />
<property name="price" value="500" />
</bean>
</beans>
测试类
package com.openlab.test;
import com.openlab.pojo.CellPhone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestData {
public static void main(String[] args) {
ApplicationContext factory=new ClassPathXmlApplicationContext("beansdata.xml");
//通过getBean()获取到beansdata.xml文件中Bean对象
CellPhone ce=factory.getBean("cellphone", CellPhone.class);
CellPhone ce2=factory.getBean("cellphone", CellPhone.class);
System.out.println(ce==ce2);
}
}
测试结果
默认单例小结
这个bean就是一个单实例(单例模式)的,即每次调用getBean()方法,获取到的都是同一个bean实例。
第二种:
scope=”prototype”
scope=“prototype” 可以保证
当有请求的时候 都创建一个对象
xml文件中加入了
scope="prototype"
<bean class="com.openlab.pojo.CellPhone" name="cellphone" scope="prototype">
<property name="name" value="小米" />
<property name="price" value="500" />
</bean>
测试结果
第三种:当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即
每个HTTP请求都会有各自的bean实例
,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
第四种:当一个bean的作用域为Session,表示
在一个HTTP Session中,一个bean定义对应一个实例
。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
第五种:当一个bean的作用域为Global Session,表示在
一个全局的HTTP Session中,一个bean定义对应一个实例
。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="user" class="com.foo.Preferences "scope="globalSession"/>
global session作用域类似于标准的HTTP Session作用域,不过仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。
4.Bean的生命周期
创建一个类BeanLife和Spring配置文件BeanLife.xml,用于测试无参构造方法、init方法和destroy的调用顺序。
五步
- BeanLife类
package com.openlab.pojo;
public class BeanLife {
/**
* @ClassName BeanLife
* @author 奋斗小新人
* @date: 2021年9月14日 16点52分
*/
private String name;
public String getName() {
System.out.println("get方法执行了");
return name;
}
public void setName(String name) {
System.out.println("调用set方法");
this.name = name;
}
public BeanLife() {
System.out.println("构造方法执行");
}
public void init(){
System.out.println("init执行了");
}
public void destroy(){
System.out.println("destory执行了");
}
}
- BeanLife.xml文件
<bean class="com.openlab.pojo.BeanLife" id="beanlife" init-method="init" destroy-method="destroy" lazy-init="true">
<property name="name" value="生命周期测试"/>
</bean>
- 测试方法和运行结果如图:
由运行结果可以知道,类中的构造方法优先调用,然后才会调用初始化函数。销毁函数只有以ClassPathXmlApplicationContext来创建对象调用getBean()方法后,调用close()函数才会执行。
七步
测试类BeaLife1类
package com.openlab.pojo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeaLife1 implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("创建之前");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("创建之后");
return bean;
}
}
xml
<bean class="com.openlab.pojo.BeanLife" id="beanlife" init-method="init" destroy-method="destroy" lazy-init="true">
<property name="name" value="生命周期测试"/>
</bean>
<bean class="com.openlab.pojo.BeaLife1" id="beanlife1" />
测试类
package com.openlab;
import com.openlab.pojo.BeaLife1;
import com.openlab.pojo.BeanLife;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("------------加载配置文件-----------------");
BeanLife beanlife = context.getBean("beanlife", BeanLife.class);
System.out.println("对象可以正常使用");
System.out.println("------从Spring容器中获取对象");
BeaLife1 beanlife1 = context.getBean("beanlife1", BeaLife1.class);
context.close();
}
}
结果
4.Spring中bean的两种
- 创建普通的Bean对象
package com.openlab;
import com.openlab.pojo.BeanLife;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanLife beanlife = context.getBean("beanlife", BeanLife.class);
}
}
2.创建工程Bean工厂
package com.openlab.pojo;
import org.springframework.beans.factory.FactoryBean;
public class Factory implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
然后通过工厂来创建队列的创建。