Hello,今天给各位童鞋们分享Spring,赶紧拿出小本子记下来吧!
Spring简介
分层的Java SE/EE应用full-stack轻量级开源框架,以IOC(反转控制)和AOP(面向切面编程)为内核
能整合开源世界众多第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架
优势:
方便解耦:通过IOC容器,将对象间的依赖关系交给Spring控制,避免编码的过度耦合
AOP编程的支持
声明式事务支持:声明式灵活管理事务,减少不必要的事务管理的代码编写
方便测试
方便集成优秀框架
降低对Java EE API的使用难度
源码是学习典范
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>
例如properties <String,String>类型的键值对
<property name="props">
<props>
<prop key="p1">aaa</prop>
<prop key="p2">bbb</prop>
</props>
</property>
引入其他配置文件,分模块开发:可以在主配置文件中通过import引入其他配置文件如果配置发生冲突,按照配置引入的先后顺序进行覆盖
简单记忆
注意:配置文件中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配置数据源(连接池)
开发步骤:
导入数据源坐标和数据库驱动坐标
创建数据源对象
设置数据源的基本连接数据
使用数据源获取连接资源和归还连接资源
原始方式配置数据源(未解耦)
读取jdbc.properties配置文件创建连接池(解耦,但没有让spring帮我们创建数据源对象)
使用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>
抽取jdbc配置文件配置数据源(解耦合,同时每个配置文件分工明确,数据库配置 和 spring配置分开了)applicationContext.xml加载jdbc.properties配置文件获得连接信息location="类加载路径:xxx.properties"
Spring注解开发(主流 重要)
注解代替xml配置
步骤:
先在类中加上注解
开启组件扫描
spring原始注解
使用注解开发时:需要在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方法,直接通过反射给目标赋值)
使用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
引入其他文件:
@Configuration //指定该类是Spring配置类,加载该类的注解
//<context:component-scan base-package="com.itheima"/>
@ComponentScan("com.itheima") //指定扫描组件的配置
@Import({DataSourceConfiguration.class}) //导入其他配置类,是个数组
public class SpringConfiguration {
}
测试类要使用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创建方法进行测试
Spring的AOP开发
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的技术
优点:在程序运行期间不修改源码的情况下进行功能增强,减少重复代码,提高效率便于维护
实现:底层通过Spring的动态代理技术实现
常用动态代理技术:
JDK代理:基于接口的动态代理技术
cglib代理:基于父类的动态代理技术
JDK动态代理
cglib动态代理
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....");
}
}
创建切面类(内部有增强方法)
将目标对象和切面对象的创建权交给Spring
在applicationContext.xml配置织入关系
XML配置AOP详解
切点表达式写法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
注意:
修饰符可以省略
除开修饰符都可以用星号 * 表示任意
包名与类名之间一个点.表示当前包下的类,两个点..表示当前包及其子包下的类
参数列表可以用两个点..表示任意个数,参数类型的参数列表
常用:execution(* com.itheima.aop ..(..))
通知的配置语法:<aop:通知类型 method="切面类中方法名" pointcut="切点表达式" />
切点表达式的抽取当多个切点表达式相同时,配置pointcut-ref属性进行抽取
<aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop..(..))"/>
<aop:before method="before" pointcut-ref="myPointcut"/>
基于注解的AOP配置
通知的配置语法:@通知注解(“切点表达式”)
步骤:
前置步骤:用@Component将 切面类 和 目标类 交给Spring创建,同时开启组件扫描
使用@Aspect标注切面类
使用@增强类型注解标注通知方法
在配置文件中配置aop自动代理aop:aspectj-autoproxy
将目标类和切面类的对象创建权交给Spring(使用注解)
在切面类中使用注解配置织入关系
在配置文件中开启组件扫描和AOP自动代理
<context:component-scan base-package="com.itheima.anno"/>
测试
解耦:切面类中,切点表达式的抽取
Spring JdbcTemplate基本使用
要导入 spring-jdbc 和 spring-tx 坐标依赖
使用Spring配置创建jdbcTemplate对象 模板
applicationContext.xml
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,因为事务控制只有一种增强)
基于注解的声明式事务控制
步骤:
前置步骤:将 AccountDaoImpl 和 AccountServiceImpl 使用注解配置
将配置增强的xm配置 使用@Transactional代替即可 可以定义在类上(控制类中所有方法),或者方法上,就近原则
applicationContext.xml
AccountServiceImpl
注意:使用注解配置时一定要记得配置事务注解驱动:tx:annotation-driven
小结
使用spring进行事务控制,主要就是利用 AOP 思想,不侵入开发的组件,通过在系统层面配置事务控制来控制业务逻辑,使 业务逻辑 和 事务控制 分开,降低耦合
好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们