上线3天遭 Github 疯狂转载的阿里首发Spring笔记,到底有多强?

178 阅读12分钟

Hello,今天给各位童鞋们分享Spring,赶紧拿出小本子记下来吧!

image.png

Spring简介

分层的Java SE/EE应用full-stack轻量级开源框架,以IOC(反转控制)和AOP(面向切面编程)为内核

能整合开源世界众多第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架

优势:

方便解耦:通过IOC容器,将对象间的依赖关系交给Spring控制,避免编码的过度耦合

AOP编程的支持

声明式事务支持:声明式灵活管理事务,减少不必要的事务管理的代码编写

方便测试

方便集成优秀框架

降低对Java EE API的使用难度

源码是学习典范

image.png Spring基本开发步骤:

导入jar包坐标

创建Javabean

创建配置文件applicationContext.xml

配置文件种进行配置

创建ApplicationContext对象调用getBean()方法

Spring的IOC开发

Spring配置文件

Bean标签基本配置

用于配置的对象交给spring创建,默认情况下调用类中的无参构造,如果没有则创建失败

基本属性:

id:Bean实例在Spring容器中的唯一标识

class:Bean的全限定名称

其他属性:

scope:对象的作用范围,singleton(单例的,默认值),prototype(多例的),request,session,global session

当scope属性为singleton时:

实例化时机:Spring核心文件被加载时(配置文件被加载时)

当scope属性为prototype时:

实例化时机:调用getBean()时

init-method:指定类中的初始化方法名称

destroy-method:指定类中的销毁方法名称

Bean实例化三种方式:

无参构造方法实例化(掌握):

工厂静态方法实例化(了解):

public class StaticFactoryBean{ public static UserDao createUserDao(){ return new UserDaoImpl(); } }

工厂实例化方法实例化(了解):

public class DynamicFactoryBean{ public UserDao createUserDao(){ return new UserDaoImpl(); } }

Bean的依赖注入入门:

创建UserService,UserService内部调用UserDao的save()方法;

将UserServiceImpl的创建全交给Spring

从Spring容器中获得UserService进行操作

分析:因为UserService和UserDao都在Spring容器中,而最终程序直接使用的是UserService,所以可以在Spring容器中,将UserDao设置到UserService内部。

Bean的依赖注入方式:

1.set方法注入:

UserServiceImpl

//在UserServiceImpl中添加setUserDao方法

pubic class UserServiceImpl implements UserService{

private UserDao userDao;

public void setUserDao(UserDao userDao) {

	this.userDao = userDao;

}

}

applicationContext.xmlproperty 的 name 属性代表的是 userService 中 set 方法的后半段也就是 userDao

<property name="userDao" ref="userDao"/>

Controller

public class UserController {

public static void main(String[] args) {

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

    UserService userService = (UserService) app.getBean("userService");

    userService.save();

}

}

注意:此时将UserDao的创建权交给了Spring,如果Controller层没有通过Spring配置文件创建UserService,而是通过自己new 一个 UserService,此时自己new 的UserService内部将没有通过set方法创建和注入DaoUser对象,因此使用UserDao.save方法会产生空指针异常

p命名空间注入(了解,属于set方式)

扩展:引入p命名空间写法,一般不常用

xmlns:p="springframework.org/schema/p"

2.构造方法注入:创建有参构造

<constuctor-arg name="userDao" ref="userDao"/>

Bean的依赖注入的数据类型(这里都是使用set方式)

1.普通数据类型例如String,在UserDaoImpl创建私有对象name和age,创建set方法

<property name="name" value="zhangsan"/>

<property name="age" value="18"/>

2.引用数据类型(上面已有)3.集合数据类型例如list

<property name="strList" value="zhangsan">

	<list>

		<value>123</value>

		<value>123</value>

		<value>123</value>

	</list>

</property>

例如map<String,User>

image.png 例如properties <String,String>类型的键值对

<property name="props">

     <props>

         <prop key="p1">aaa</prop>

         <prop key="p2">bbb</prop>

     </props>

 </property>

引入其他配置文件,分模块开发:可以在主配置文件中通过import引入其他配置文件如果配置发生冲突,按照配置引入的先后顺序进行覆盖

简单记忆

image.png 注意:配置文件中property的name

用set方法注入,name:set方法后半段的属性值 (setUserDao => userDao)

用构造方法,name:要传入的参数名 (传入userDao => userDao)

依赖注入引用对象:配置 ref 属性

依赖注入普通对象:配置 value 属性 (String类型也是直接配value)

依赖注入普通对象如果是集合类型,要根据集合类型配置不同属性

如:List类型的注入 要配置属性,list属性中再配置相应对象;Map类型的注入 要配置属性,其中由键值对组成,所以再配属性

Spring相关API

ApplicationContext:接口类型,代表应用上下文,可以通过实例获得Spring容器中的Bean对象

ApplicatioContext实现类:

ClassPathXmlApplicationContext:从类的根路径下加载配置文件,推荐使用

FileSystemXmlApplicationContext:从磁盘路径上加载配置文件,配置文件可以在磁盘任意位置,不常用

AnnotationConfigApplicationContext:使用注解配置容器对象时,使用此类来创建Spring容器,同来读取注解

getBean()方法:

参数类型为String时,标识根据Bean的id从容器中获得Bean实例,返回Object

参数类型为Class类型时,根据类型从容器中获取Bean实例,不能用于容器中有多个相同类型的Bean

Spring配置数据源(连接池)

开发步骤:

导入数据源坐标和数据库驱动坐标

创建数据源对象

设置数据源的基本连接数据

使用数据源获取连接资源和归还连接资源

原始方式配置数据源(未解耦)

image.png 读取jdbc.properties配置文件创建连接池(解耦,但没有让spring帮我们创建数据源对象)

image.png 使用Spring配置数据源

将DataSource的创建权交给Spring容器去完成(解耦合,但同时配置文件分工不够明确)

DataSource有无参构造方法,Spring时默认通过无参构造方法实例化对象

DataSource还需要通过set方法设置数据库连接信息,Spring可以通过set方法注入

<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>

<property name="url" value="jdbc:mysql://localhost:3306/test"></property>

<property name="username" value="root"></property>

<property name="password" value="root"></property>

image.png 抽取jdbc配置文件配置数据源(解耦合,同时每个配置文件分工明确,数据库配置 和 spring配置分开了)applicationContext.xml加载jdbc.properties配置文件获得连接信息location="类加载路径:xxx.properties"

image.png

Spring注解开发(主流 重要)

注解代替xml配置

步骤:

先在类中加上注解

开启组件扫描

spring原始注解

image.png 使用注解开发时:需要在applicationContext.xml中配置组件扫描,作用时指定那个包及其子包下的Bean需要进行扫描以便试别需要使用注解配置的类,字段和方法

<context:component-scan base-package="com.itheima"/>

使用@Component或者@Repository标识UserDaoImpl进行Spring实例化

//

//@Component("userDao")

@Repository("userDao")

public class UserDaoImpl implements UserDao {

public void save() {

    System.out.println("save running...");

}

}

使用@Component或者@Service标识UserServiceImpl进行Spring实例化

使用@Value进行字符串的注入

使用@Autowired或者@Autowired+@Qualifier或者@Resource进行userDao的注入

(使用注解注入可以不需要set方法,直接通过反射给目标赋值)

image.png 使用Scope标注Bean的范围

@Scope("singleton")

public class UserDaoImpl implements UserDao{

}

注意

在要依赖注入属性前只写Autowired时,是Spring按照该数据类型从Spring容器中匹配的,

例如:当前需要一个userDao对象,然后Spring中正好将UserDaoImpl默认singleton注入了,所以就可以使用,但如果有多个对象,就会出问题

即:按照类型注入:@Autowired;按照 id 注入:@Autowired + @Qualifier("xxx")

使用注解注入对象可以不需要set方法,直接通过反射找到目标对象,给目标赋值

@Value("${jdbc.driver}")Value一般配合SpEL使用,来注入Spring配置文件中的一些普通变量

Spring新注解

使用原始注解还不能全部代替xml文件,还需要新注解

非自定义的Bean配置:

加载properties文件的配置:context:property-placeholder

扫描组件的配置:context:component-scan

引入其他文件:

image.png @Configuration //指定该类是Spring配置类,加载该类的注解

//<context:component-scan base-package="com.itheima"/>

@ComponentScan("com.itheima") //指定扫描组件的配置

@Import({DataSourceConfiguration.class}) //导入其他配置类,是个数组

public class SpringConfiguration {

}

image.png 测试类要使用AnnotationConfigApplicationContext类指定配置类名称,获得ApplicationContext对象

public class controller {

public static void main(String[] args)  {

    ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class);

    UserService userService = app.getBean(UserService.class);

    userService.save();

}

}

Spring集成Junit

每个测试类中,每个测试方法都会有下面两行代码

ApplicationContext app = new ClassPathXmlApplicationContext("bean.xml");

Object o = app.getBean(xxx.class);

这两行的代码作用是获取容器,不写的话,提示空指针异常,所以不能轻易删掉

解决思路:让SpringJunit负责创建Spring容器,但是需要将配置文件名字告诉它,将需要进行测试的bean直接在测试类中注入

Spring继承Junit步骤:

导入Spring集成Junit的坐标:spring-test

使用@Runwith注解替换原来的运行期

使用@ContextConfiguration指定配置文件或配置类

使用@Autowired注入需要测试的对象

使用@Test创建方法进行测试

image.png

Spring的AOP开发

面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的技术

优点:在程序运行期间不修改源码的情况下进行功能增强,减少重复代码,提高效率便于维护

实现:底层通过Spring的动态代理技术实现

常用动态代理技术:

JDK代理:基于接口的动态代理技术

cglib代理:基于父类的动态代理技术

image.png JDK动态代理

image.png cglib动态代理

image.png

AOP相关概念

Spring的AOP实现底层就是对上面的动态代理代码进行了封装

AOP相关术语:

Target(目标对象):要代理的目标对象

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

Joinpoint(连接点):被拦截到的方法,可以被增强的方法

Pointcut(切入点):要被增强的方法,实际被增强的方法

Advice(通知、增强):增强方法

Aspect(切面):Pointcut+Advice

Weaving(织入):动态代理的过程

AOP底层使用哪种代理方式:Spring中,会根据目标类是否实现了接口来决定采用哪种方式

开发明确:

谁是切点(切点表达式的配置)

谁是通知(切面类中的增强方法)

将切点和通知进行织入配置

基于XML的AOP开发快速入门

步骤:

导入AOP相关坐标(aspectj)

创建目标接口和目标类(内部有切点)

创建切面类(内部有增强方法)

将目标类和切面类的创建权交给Spring

在applicationContext.xml中配置织入关系

测试

导入AOP相关坐标

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.0.5.RELEASE</version>
<groupId>org.aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

<version>1.8.4</version>

创建目标接口和目标类

public interface TargetInterface {

public void save();

}

public class Target implements TargetInterface {

public void save() {

    System.out.println("save running....");

}

}

创建切面类(内部有增强方法)

image.png

将目标对象和切面对象的创建权交给Spring

在applicationContext.xml配置织入关系

image.png

XML配置AOP详解

切点表达式写法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))

注意:

修饰符可以省略

除开修饰符都可以用星号 * 表示任意

包名与类名之间一个点.表示当前包下的类,两个点..表示当前包及其子包下的类

参数列表可以用两个点..表示任意个数,参数类型的参数列表

常用:execution(* com.itheima.aop ..(..))

通知的配置语法:<aop:通知类型 method="切面类中方法名" pointcut="切点表达式" />

image.png 切点表达式的抽取当多个切点表达式相同时,配置pointcut-ref属性进行抽取

<aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop..(..))"/>

<aop:before method="before" pointcut-ref="myPointcut"/>

基于注解的AOP配置

image.png

通知的配置语法:@通知注解(“切点表达式”)

步骤:

前置步骤:用@Component将 切面类 和 目标类 交给Spring创建,同时开启组件扫描

使用@Aspect标注切面类

使用@增强类型注解标注通知方法

在配置文件中配置aop自动代理aop:aspectj-autoproxy

将目标类和切面类的对象创建权交给Spring(使用注解)

在切面类中使用注解配置织入关系

image.png

在配置文件中开启组件扫描和AOP自动代理

<context:component-scan base-package="com.itheima.anno"/>

aop:aspectj-autoproxy/

测试

image.png

解耦:切面类中,切点表达式的抽取

image.png

Spring JdbcTemplate基本使用

要导入 spring-jdbc 和 spring-tx 坐标依赖

使用Spring配置创建jdbcTemplate对象 模板

applicationContext.xml

image.png jdbc.properties

jdbc.driverClassName=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/test

jdbc.username=root

jdbc.password=root

jdbcTemplate 常用方法

int row = update(sql, ...args)常用于 add delete update 操作,返回影响的行数

List list= query(sql, new BeanRowMapper()) 常用于查询多条记录,返回 list 集合

Object o = queryForObject(sql, new BeanRowMapper()) 常用于查询单行,返回一个指定对象

Long count = queryForObject(sql, Long.class) 用于查询记录的数量,返回数量(可以是Integer或者Long)

Spring的事务控制

编程式事务控制

三大对象

PlatformTransactionManager:平台事务管理接口

实现是根据不同的Dao层的技术而实现的,不同的平台事务管理器内部封装的控制事务的方式,API 都不一样,(需要通过配置的方式指定)

TransactionDefinition:事务定义对象,封装一些事务的参数

隔离级别,传播行为 (需要通过配置的方式指定)

TransactionStatus:事务状态

随着事件的进行,内部的信息会跟着相应的改变 (不需要通过配置的方式改变)

声明式事务控制

作用:不侵入开发的组件,类似于AOP思想,通过在系统层面配置事务控制来控制业务逻辑,使 业务逻辑 和 事务控制 分开,降低耦合,改变事务时,也只需要在配置文件中更改即可。

Spring中声明式事务控制底层就是AOP

基于xml的声明式事务控制

步骤:

前置步骤:配置dataSource和jdbcTemplate,还有 AccountDaoImpl 以及 AccountServiceImpl

配置平台事务管理器 (要依赖于dataSource)

配置增强 (指定事务管理器,指定每个被事务控制的方法事务属性 如:隔离级别、传播行为等)

配置织入 (使用aop:advisor,因为事务控制只有一种增强)

image.png

基于注解的声明式事务控制

步骤:

前置步骤:将 AccountDaoImpl 和 AccountServiceImpl 使用注解配置

将配置增强的xm配置 使用@Transactional代替即可 可以定义在类上(控制类中所有方法),或者方法上,就近原则

applicationContext.xml

image.png AccountServiceImpl

image.png

注意:使用注解配置时一定要记得配置事务注解驱动:tx:annotation-driven

小结

使用spring进行事务控制,主要就是利用 AOP 思想,不侵入开发的组件,通过在系统层面配置事务控制来控制业务逻辑,使 业务逻辑 和 事务控制 分开,降低耦合

好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们