写此系列的目的是做一个学习笔记管理,方便以后复习用。
Spring是轻代码,重配置的框架。
Spring是分层的 Java SE/EE应用 full-stack 轻量级(重量级)开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。
提供了展现层 SpringMVC 和持久层 Spring JDBCTemplate 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
Spring框架的核心功能:
创建管理所有的Java对象,这些对象被称为Bean。
Spring快速入门
导入Spring开发的基本包坐标
pom.xml
1
2
3
4
5
6
7
8
9
10
11
12<properties>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<!--导入spring的context坐标,context依赖core、beans、expression-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
编写Dao接口和实现类
1
2
3
4
5
6
7
8
9
10public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("UserDao save method running....");
}
}
创建Spring核心配置文件
在类路径下(resources)创建applicationContext.xml配置文件
1
2
3
4
5
6
7
<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">
</beans>在Spring配置文件中配置UserDaoImpl
1
2
3
4
5
6
7
8
9
<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="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
</beans>
使用Spring的API获得Bean实例
1
2
3
4
5
6
7
public void test1(){
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
Spring配置文件
重要配置标签
1 | <bean>标签 |
Bean实例化的三种方式
无参构造方法实例化
1 | <bean id = "userDao" class = "com.itheima.dao.impl.UserDaoImpl"></bean> |
工厂静态方法实例化
工厂实例方法实例化
Bean的依赖注入
依赖注入(Dependency Injection):它是 Spring 框架核心 IOC(反转控制) 的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。
IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
用依赖注入的方式管理Bean之间的依赖关系。依赖注入可以让Bean以配置文件组织在一起,是一种优秀的解耦方式。
依赖注入有两种方式,set注入和构造注入。(设计模式解耦合)
set注入和构造注入
1 | <!--set方式注入--> |
相关API
applicationContext:接口类型,代表应用上下文,可以通过其实例获得 Spring 容器中的 Bean 对象
ApplicationContext的实现类
1)ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件 推荐使用这种
2)FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
3)AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
1 | ApplicationContext app = new ClasspathXmlApplicationContext("xml文件"); |
Spring配置数据源(连接池)
druid步骤:
导入依赖 pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
<scope>compile</scope>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!--导入Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--版本要求高于4.11-->
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>创建DataSource 在Spring中采用注入容器的方法 applicationContext.xml
1
2
3
4
5
6<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/db1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>将参数提取到properties文件中后如何注入容器
1.需要引入context的命名空间和约束路径
- 命名空间
xmlns:context="http://www.springframework.org/schema/context" - 约束路径
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd - applicationContext.xml
1
2
3
4
5
6
7
8
9
10
11<!--加载外部配置文件,classpath是从类加载文件resources中加载-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--注入datasource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--spl表达式,类似el表达式的用法 value="${key}"-->
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>- 命名空间
使用
1
2
3
4
5
6
7
8
9
public void test2() throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");//加载Spring的配置文件
//从容器中获取对象
DataSource ds = (DataSource) applicationContext.getBean("dataSource");
Connection conn = ds.getConnection();
System.out.println(conn);
conn.close();
}
注解开发
简化和舍弃Spring的配置文件,方便快捷
原始注解
@Component
<bean id="userDao" class="com.tsuki.dao.impl.UserDaoImpl"></bean>@Controller @Service @Repository
@Autowired @Qualifier---@Resource按名称注入
1
2
3<bean id="userService" class="com.tsuki.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>@Value(普通属性) @Scope
配置组件扫描
1
2<!--配置组件扫描-->
<context:component-scan base-package="com.tsuki" />新注解开发—全注解开发
旧注解有几方面不能满足
@ConfigurationSpring的核心配置类,用类的方式替代xml文件, 注解的方式替代标签- 非自定义的bean
@Bean("dataSource") - 配置文件properties
@PropertySource("classpath:jdbc.properties") - 组件扫描
@ComponentScan("com.tsuki") - 引入import
@Import
- 非自定义的bean
Junit的集成
导入spring集成Junit坐标 pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<!--导入Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--版本要求高于4.11-->
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!--导入spring的test坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>@Runwith代替原来运行周期
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration指定配置文件或配置类
@ContextConfiguration("classpath:applicationContext.xml")@Autowired注入需要测试的对象
创建测试方法进行测试
AOP
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
用到了代理模式,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。
常见的动态代理技术有JDK代理和cglib代理,代码上的区别就是需不需要接口。
动态代理代码
1 | Target target = new Target(); //创建目标对象 |
基于xml
快速入门
导入坐标
1
2
3
4
5
6
7
8
9
10
11
12<!--导入spring的context坐标,context依赖aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!-- aspectj的织入 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>创建目标接口和目标类(内部有切点)
创建切面类(内部有增强方法)
将目标类和切面类的对象创造权交给spring
在applicationContext.xml配置织入关系
测试
重要标签
切点表达式的写法
execution(public void com.tsuki.aop.Target.method())
通知的类型: aop:before aop:after-returning aop:around aop:throwing aop:after
织入
1 | <aop:config> |
基于注解
快速入门
创建目标接口和目标类
创建切面类
将目标类和切面类的对象创建交给spring
在切面类中使用注解配置织入关系
1
2
3
4
5
6
7
8("myAspect")//步骤3
public class MyAspect {
("execution(* com.itheima.aop.*.*(..))")
public void before(){
System.out.println("前置代码增强.....");
}
}在配置文件中开启组件扫描和AOP自动代理
1
2
3
4
5<!--组件扫描-->
<context:component-scan base-package="com.itheima.aop"/>
<!--aop的自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>测试
重要标签
注解通知常见的类型
@Before @AfterReturning @Around @AfterThrowing @After
事务控制
编程式事务控制三大对象
- PlatformTransactionManager
- TransactionDefinition
- TransactionStatus
声明式事务控制
Spring 声明式事务控制底层就是AOP。
Spring并不直接管理事务,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,也就是将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
基于注解和xml方式实现。
事务隔离级别
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITTED 未提交读
ISOLATION_READ_COMMITTED 已提交读
ISOLATION_REPEATABLE_READ 可重复读
ISOLATION_SERIALIZABLE 串行化(通过加锁来实现)
事务传播行为
REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
通过这两个方法我们证明了在外围方法未开启事务的情况下
Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。以上试验结果我们证明在外围方法开启事务的情况下
Propagation.REQUIRED修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
通过这两个方法我们证明了在外围方法未开启事务的情况下
Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。在外围方法开启事务的情况下
Propagation.REQUIRES_NEW修饰的内部方法依然会单独开启独立事务,且与外部方法事务也独立,内部方法之间、内部方法和外部方法事务均相互独立,互不干扰。NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
通过这两个方法我们证明了在外围方法未开启事务的情况下
Propagation.NESTED和Propagation.REQUIRED作用相同,修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰以上试验结果我们证明在外围方法开启事务的情况下
Propagation.NESTED修饰的内部方法属于外部事务的子事务,外围主事务回滚,子事务一定回滚,而内部子事务可以单独回滚而不影响外围主事务和其他子事务