众所周知,Spring 是目前市面上最主流的一款功能非常强大的框架,中文意思是春天,也让我们开发人员从JSP、sevlet的高耦合的开发中彻底的解救出来。废话少说,接下来就进行详细介绍。
【1】Spring是什么
Spring是一个开源框架,Spring的核心是控制反转(IOC)和面向切面(AOP)。
简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
轻量级:与EJB对比,依赖资源少,销毁的资源少。
分层: 一站式,每一个层都提供的解决方案
- web层:struts2,spring-MVC
- service层:spring
- dao层:hibernate,mybatis , jdbcTemplate --> spring-data
【2】Spring优势
Spring 出现是为了解决JavaEE 实际问题:
-
方便解耦,简化开发 (IOC)
Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
Spring工厂是用于生成bean
-
AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
-
声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
-
方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
-
方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
-
降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
基于这些特性,我们也会俗称Spring为开发架构的粘合剂。
【3】Spring体系结构
可以访问官网进行自主学习:https://spring.io/
Spring框架至今已集成了20多个模块,这些模块分布在以下模块中:
核心容器(Core Container)
数据访问/集成(Data Access/Integration)层
Web层
AOP(Aspect Oriented Programming)模块
植入(Instrumentation)模块
消息传输(Messaging)
测试(Test)模块
【4】Spring核心
- 控制反转(Inversion of Control,IOC)
- 面向切面编程(aspect-oriented programming,AOP)
Spring所有功能都依赖于这两个核心
注意:IOC和AOP并不是一种技术,而是一种思想,这点要清楚。
接下来就来讲一下IOC
【5】IOC
IOC介绍:IOC 全称为 Inversion of Control,翻译为 “控制反转”。
控制:控制对象的创建与销毁
反转:将对象的控制权(创建与销毁)交给Spring的IOC容器。
作用:解耦。
由于Java是面向对象开发,开发过程中由N个对象构成,各对象互相合作完成需求。但是此过程存在一个很大的问题,就是各个对象间耦合度太高,导致后期维护困难。
而Spring提供了一种IOC思想,就是引用“第三方”:IOC容器实现具有依赖关系的对象之间的解耦。全部对象的控制权都交给IOC容器,包括创建、销毁,这样各对象间就解除了关系,独立存在。
其他解释:
什么是ioc:控制反转,以前我们要获取对象,我们自己new.主动获取。现在有了工厂模式,我们需要获取对象,是工厂创建,我们被动接受工厂创建的对象.这就是控制反转.说白了ioc就是工厂模式.
spring框架提供了一个大工厂接口:ApplicationContext(父接口Beanfactroy)
spring-IOC的配置采取的是什么类型?
spring使用XML格式的文件存储配置
<bean id="唯一标识"
class="实现类的全限定名">
</bean>
spring-IOC是怎么加载配置文件的呢?
ApplicationContext工厂使用ClassPathXmlApplicationContext加载配置文件
基于多个实现类需要进行功能切换,我们只需要修改配置文件,不需要改java代码,所以不需要重新编译。
【6】IOC的XML开发
使用一个入门小案例来讲解
使用ApplicationContext:spring-IOC容器创建对象
1.配置pom.xml,引入spring-context依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.vv.spring</groupId>
<artifactId>spring-ioc</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring-ioc</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- spring版本 -->
<spring.version>5.1.11.RELEASE</spring.version>
</properties>
<dependencies>
<!--spring ioc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.编写配置文件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.xsd">
<!--bean
作用:
声明类交给spring容器
属性:
id: 唯一标识
class:全路径限定名称
细节:
默认使用无参构造函数实例化-->
<bean id="accountDao" class="com.vv.spring.dao.Impl.AccountDaoImpl"/>
<bean id="accountService" class="com.vv.spring.service.Impl.AccountServiceImpl"/>
</beans>
3.通过spring的工厂获取对象
public class SpringTest {
public static void main(String[] args) {
//1.创建spring的工厂
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//2.通过spring的工厂获取对象
Object userService = ac.getBean("userService");
System.out.println(userService);
}
}
bean标签详解
<?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 definitions here -->
<!--
bean标签: 创建对象,将对象装配到spring容器(泛指spring工厂类)。
id: 对象的唯一标识
class:实现类的路径,底层就是通过反射机制创建对象的。
init-method: 对象创建时,要调用的初始化方法
destroy-method: 对象销毁时,要调用的销毁方法
scope:用来配置bean的作用域
singleton: 单例(默认)
prototype: 多例
对象的生命周期:
applicationContext: 工厂初始化时,对象就创建完毕。(单例情况下)
单例:
工厂初始化时创建对象。
只要工厂存在,对象就存在。
工厂销毁,对象销毁。
多例:
什么时候用,什么时候创建。
工厂存在,对象存在。
工厂销毁,对象不销毁。对象只能等待垃圾回收机制回收。
-->
<bean id="userService" scope="prototype" init-method="init" destroy-method="destroy" class="com.itheima.service.impl.UserServiceImpl"></bean>
</beans>
UserServiceImpl
Test
public class SpringTest {
public static void main(String[] args) {
System.out.println("************工厂初始化start***********");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("************工厂初始化end*************");
//通过spring的工厂获取对象
Object userService = ac.getBean("userService");
Object userService2 = ac.getBean("userService");
System.out.println(userService);
System.out.println(userService2);
//销毁工厂
System.out.println("*************销毁工厂*****************");
ac.close();
}
}
运行结果:
创建对象的4种方式
<?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">
<!--
spring创建对象的4种方式
1.默认 无参构造
2.工厂类的静态方法
3.工厂类的动态方法
4.BeanFactory接口方式,后面ssm整合再去介绍
-->
<!-- 默认无参构造方式-->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl"></bean>
<!-- 工厂类的静态方式 -->
<bean id="userService2" class="com.vv.utils.BeanFactory" factory-method="getUserService"></bean>
<!-- 工厂类的动态方法-->
<bean id="factoryBean2" class="com.vv.utils.BeanFactory2"></bean>
<bean id="userService3" factory-bean="factoryBean2" factory-method="getUserService" ></bean>
</beans>
public class UserServiceImpl implements UserService {
//无参构造
public UserServiceImpl() {
System.out.println("UserServiceImpl的无参构造被调用了");
}
}
public class BeanFactory {
//工厂类的静态方法
public static UserService getUserService(){
System.out.println("工厂类的静态方法");
return new UserServiceImpl();
}
}
public class BeanFactory2 {
//工厂类的动态方法
public UserService getUserService(){
System.out.println("工厂类的动态方法");
return new UserServiceImpl();
}
}
【7】spring的依赖注入DI
Dependency Injection (依赖注入):
spring创建对象的时候,给对象的属性赋值,就是依赖注入。
注意是spring创建对象!!!
方式一:有参构造
applicationContext.xml
<!-- 有参构造方式-->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl">
<!--
给哪个属性赋什么值
确定属性
name: 通过属性名确定属性
index: 通过索引来确定属性
type: 通过属性的类型确定属性
赋值:
value:基本类型的赋值
ref: 引用型类型的赋值
-->
<constructor-arg name="age" value="23" ></constructor-arg>
<constructor-arg name="game" value="LOL"></constructor-arg>
<constructor-arg name="username" value="张三"></constructor-arg>
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
<!-- 有参构造方式-->
<bean id="userService2" class="com.vv.service.impl.UserServiceImpl">
<constructor-arg index="1" value="23" ></constructor-arg>
<constructor-arg index="2" value="LOL"></constructor-arg>
<constructor-arg index="0" value="张四"></constructor-arg>
<constructor-arg index="3" ref="userDao"></constructor-arg>
</bean>
<!-- 有参构造方式-->
<bean id="userService3" class="com.vv.service.impl.UserServiceImpl">
<constructor-arg type="java.lang.Integer" value="23" ></constructor-arg>
<constructor-arg type="java.lang.String" value="王五"></constructor-arg>
<constructor-arg type="java.lang.String" value="LOL"></constructor-arg>
<constructor-arg type="com.vv.dao.UserDao" ref="userDao"></constructor-arg>
</bean>
UserServiceImpl
public class UserServiceImpl implements UserService {
private String username;
private Integer age;
private String game;
private UserDao userDao;
//有参构造
public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
this.username = username;
this.age = age;
this.game = game;
this.userDao = userDao;
}
public UserServiceImpl() {
}
@Override
public void login() {
userDao.findUserByUser();
}
}
Test
public class SpringTest {
//这是一个servlet
public static void main(String[] args) {
//调用service的方法
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService)ac.getBean("userService");
userService.login();
}
}
方式二:set方法
applicationContext.xml
<!-- 属性的set方法 -->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl">
<!--
name:用来确定属性的。
name属性的值是set的方法名去掉set后的驼峰命名名字。
value:基本类型的属性赋值
ref:引用型类型的属性赋值
-->
<property name="username" value="赵六"></property>
<property name="age" value="25"></property>
<property name="game" value="王者荣耀"></property>
<property name="userDao" ref="userDao"></property>
</bean>
UserServiceImpl
public class UserServiceImpl implements UserService {
private String username;
private Integer age;
private String game;
private UserDao userDao;
public UserServiceImpl(String username, Integer age, String game, UserDao userDao) {
this.username = username;
this.age = age;
this.game = game;
this.userDao = userDao;
}
public void setUsername(String username) {
this.username = username;
}
public void setAge(Integer age) {
this.age = age;
}
public void setGame(String game) {
this.game = game;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserServiceImpl() {
}
@Override
public void login() {
userDao.findUserByUser();
}
}
Test
public class SpringTest {
//这是一个servlet
public static void main(String[] args) {
//调用service的方法
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = (UserService)ac.getBean("userService");
userService.login();
}
}
使用名称空间简写依赖注入
注入复杂类型的依赖
UserServiceImpl
public class UserServiceImpl2 implements UserService {
private String[] gameNames;
private List<String> dogType;
private Set<String> catType;
private Map<String,String> map;
public void setGameNames(String[] gameNames) {
this.gameNames = gameNames;
}
public void setDogType(List<String> dogType) {
this.dogType = dogType;
}
public void setCatType(Set<String> catType) {
this.catType = catType;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public void login(){
}
}
applicationContext.xml
<!--复杂类型的注入-->
<bean id="userService" class="com.vv.service.impl.UserServiceImpl2">
<property name="gameNames">
<array>
<value>LOL</value>
<value>PUBG</value>
<value>王者荣耀</value>
</array>
</property>
<property name="dogType">
<list>
<value>博美</value>
<value>柴犬</value>
<value>哈士奇</value>
</list>
</property>
<property name="catType">
<set>
<value>英短</value>
<value>橘猫</value>
<value>无毛猫</value>
</set>
</property>
<property name="map">
<map>
<entry value="科比" key="name"></entry>
</map>
</property
</bean>
【8】JdbcTemplate
Spring提供的JdbcTemplate和mybatis框架一样,都是对jdbc的封装,用于支撑持久层的操作,但企业开发中mybatis应用较广。
下面就对JdbcTemplate的用法进行简单介绍。
步骤:
1、搭建数据库环境;
2、创建工程导入依赖
<dependencies>
<!-- spring的jdbcTemplate相关,注意,spring技术的所有版本要保证统一-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- spring的ioc相关-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<!-- mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
3、创建pojo层
4、实现dao层接口和实现类
5、实现service层接口和实现类
6、通过配置文件实现IOC和依赖注入
<?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">
<!--accountService-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!--注入accountDao-->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--accountDao-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<!--依赖注入jdbcTemplate-->
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--jdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--依赖注入数据源-->
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
<!--创建数据源对象-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- set方法依赖注入-->
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="url" value="jdbc:mysql://localhost:3306/itheima115_spring_day02"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
</beans>
7、创建测试用例完成测试
8、优化-加载外部数据源
pom.xml
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- c3p0-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--dbcp-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
applicationContext.xml
<!--德鲁伊连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- set方法依赖注入-->
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClass}"></property>
</bean>
<!--c3p0-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- set方法依赖注入-->
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
</bean>
<!--dbcp-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!-- set方法依赖注入-->
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClass}"></property>
</bean>
【9】IOC的注解开发
注解开发的优点:提高开发效率。
主要分为下面几个类型使用:
创建对象:@component; @Controller; @Service; @Repository;
依赖注入:@Autowired; @Qualifier; @Resource(name=beanid); @Value;
生命周期:@Scope; @PostConstruct; @PreDestroy;
纯注解开发相关:@Configuration; @ComponentScan; @PropertySource; @Import; @Bean
Spring整合单元测试:@RunWith; @ContextConfiguration;
具体的使用方法还没来得及总结,有空发出来。