目录
Spring概念
Spring优势
体系结构
Spring IOC
开发步骤
Spring的相关API
ApplicationContext的相关继承体系
Bean标签配置
基本配置
范围配置
生命周期配置
实例化三种方法
Bean的依赖注入
引入其他配置文件
Spring配置数据源
数据源(连接池的作用)
数据源的开发步骤
Spring配置数据源
Spring JdbcTemplate
概述
JdbcTemplate开发步骤
spring产生JdbcTemplate对象
JdbcTemple的CURD操作
Spring 注解开发
Spring原始注解
Spring新注解
Spring集成Junit
Spring AOP
概念
AOP的作用以其优势
AOP的底层实现
JDK动态代理方法
Cglib的动态代理
AOP相关概念
基于XML的AOP开发
开发步骤
切点表达式
通知类型
基于注解的AOP开发
开发步骤
注解通知的类型
切点表达式的抽取
Spring的事务控制
编程式事务控制相关对象
PlatformTransactionManager
TransactionDefinition
TransactionStatus
基于XML的声明式事务控制
定义
声明式事务处理的作用
声明式事务控制的实现
基于注解的声明式事务控制
使用注解配置声明式事务控制
注解配置声明式事务控制解析
Spring是分层的JavaSE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming: 面向切面编程)为内核。
提供了展示层SpringMVM和持久层Spring JDBCTemplate 以及业务层事务管理等众多的企业应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。
步骤一:导入Spring开发的基本包maven坐标
org.springframework
spring-context
5.0.5.RELEASE
org.springframework
spring-test
5.0.5.RELEASE
步骤二:编写Dao/Mapper接口和实现类
步骤三:创建Spring核心配置文件(applicationContext.xml)
步骤四:在spring配置文件中配置相关Bean实体对象
步骤五:使用Spring的API获得Bean实例
ApplicationContext:接口类型、代表应用上下文,可以通过其实例获得Spring容器中的Bean对象
ApplicationContext的实现类
ApplicationContext有很多,以下介绍三种实现类
①ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件
②FIleSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
③AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建Spring容器。它用来读取注解。
getBean()方法使用
①当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object需要强转。
②当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会把报错。
Spring框架最重要就是配置Bean标签
用于配置对象交由Spring来创建
默认情况下它调用的是类中的无参构造器,如果没有无参构造函数则不能创建成功。
基本属性:
id:Bean 实例在Spring容器中的唯一标识
class:Bean的全限定名称
用UserDaoImpl举例
步骤一:创建UserDaoImpl
//定义实现类
public class UserDaoImpl implements UserDao {
//默认情况下创建空参
public UserDaoImpl(){
System.out.println("UserDaoImpl创建完成");
}
@Override
public void save() {
System.out.println("保存成功");
}
}
配置applicationContext.xml文件
使用相关API,调用Bean
public void test1(){
//在资源路径下查找配置文件
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
//调用相关方法
userDao.save();
}
scope:指对象的作用范围,取值如下:
①当scope的取值为singleton时
Bean的实例化个数为1个
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
Bean的生命周期:
a.对象创建:当应用加载,创建容器时,对象被创建了
b.对象运行:只要容器时,对象一直活着
c.对象销毁:当应用卸载,销毁容器时,对象就被销毁了
②当scope的取值为prototype时
Bean的实例化个数为多个
Bean的生命周期:当调用getBean()方法时实例化Bean
a.对象创建:当调用getBean()方法时实例化Bean
b.对象运行:只要对象在使用中,就一直活着
c.对象销毁:当对象长时间不用时,被java的垃圾回收器回收了。
默认情况下scope值为singleton
init-method:指定类中的初始化方法名称
destory-method:指定类中销毁方法名称
①无参构造方法实例化
②工产静态方法实例化
创建工厂类
public class StaticFactoryBean {
public static UserDao createUserDao(){
return new UserDaoImpl();
}
}
相关配置
③工厂实例方法实例化
创建工厂类
public class DynamicFactoryBean {
public UserDao createUserDao(){
return new UserDaoImpl();
}
}
相关配置
定义:它是Spring框架核心IOC的具体实现。在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IOC解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。那些这种业务员和持久层的依赖关系,在使用Spring之后,就让Spring来维护了,简单来说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
以下是注入方法
①Set方法注入
也采用P命名空间代替Set方法注入
P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件汇总,如下:首先,需要引入P命名空间:
xmlns:p="http://www.springframework.org/schema/p"
其次,需要修改注入方法
②有参构造器注入
④普通数据类型的注入
说明:普通数据类型注入时用value,实体类型注入时要ref
⑤集合的注入
a.List注入
小花
小咪
采用标签进行注入
b.Map的注入
采用
c.properties的注入
小黄
10
使用
实际开发时,String的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置到其他配置文件中,而在spring主配置文件通过import标签进行加载。
使用方式如:
当个方来说,就像餐厅里面的服务员,当餐厅来客人时,就有一个服务员来帮忙客人的点餐,送餐等,当客户用餐结束后离开,服务员也就可以回到之前的位置中,等待下一个客人。
数据源是指餐厅,存放着连接对象,而连接对象就指着是服务员,当一个请求来时,就会从连接池中拿出一个连接对象进行处理。处理完后,再将连接对象放回到数据源中。这样就可以减少每次连接数据库时的开销,不需要每次去请求数据库的连接。
①导入数据源的坐标和数据库驱动坐标
mysql
mysql-connector-java
8.0.25
com.mchange
c3p0
0.9.5.2
com.alibaba
druid
1.1.10
②创建数据源对象
③设置数据源的基本连接数据
④使用数据获取连接资源和归还连接资源
//加载配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\main\\resources\\jdbc.properties"));
String driver = properties.getProperty("jdbc.driver");
String url = properties.getProperty("jdbc.url");
String user = properties.getProperty("jdbc.user");
String password = properties.getProperty("jdbc.password");
//创建连接对象
DruidDataSource dataSource = new DruidDataSource();
//配置连接
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
//归还连接
connection.close();
可以将DataSource的创建权交由Spring容器去完后。
首先,需要引入context命名空间和约束路径
命名空间:xmlns:context = "http://www.springframework.org/schema/context"
约束路径:http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
spring中也提供一些jdbc的方法就是JdbcTemplate
它是spring框架中提供的一个对象,是对原始繁琐的jdbc API对象的简单封装。Spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。
①导入Spring-jdbc和spring-tx坐标
②创建数据库表和实体
③创建JdbcTemplate对象
④执行数据库操作
我们可以JdbcTemplate的创建全交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模板对象中。
①Insert操作
public void Test01(){
//导入applicationContext.xml文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//调用容器中的JdbcTemplate对象
JdbcTemplate jdbcTemplate =
(JdbcTemplate) applicationContext.getBean("jdbcTemplate");
//测试
jdbcTemplate.update("insert into account values(?,?)","xiaoha",3000);
}
②update操作
@Test
//更新操作
public void Test02(){
//导入applicationContext.xml文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//调用容器中的JdbcTemplate对象
JdbcTemplate jdbcTemplate =
(JdbcTemplate) applicationContext.getBean("jdbcTemplate");
//测试
jdbcTemplate.update("update account set money = ? where name = ?",5000,"xiaoha");
}
③delete操作
public void Test03(){
//导入applicationContext.xml文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//调用容器中的JdbcTemplate对象
JdbcTemplate jdbcTemplate =
(JdbcTemplate) applicationContext.getBean("jdbcTemplate");
//测试
jdbcTemplate.update("delete from account where name = ?","xiaoha");
}
④select操作
a.查询所有/多条数据
public void Test04(){
//导入applicationContext.xml文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//调用容器中的JdbcTemplate对象
JdbcTemplate jdbcTemplate =
(JdbcTemplate) applicationContext.getBean("jdbcTemplate");
//测试
List accountList =
jdbcTemplate.query("select * from account",
new BeanPropertyRowMapper<>(Account.class));
for (Account account : accountList) {
System.out.println(account);
}
}
b.查询一条数据
@Test
//查询一条记录
public void Test05() {
//导入applicationContext.xml文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//调用容器中的JdbcTemplate对象
JdbcTemplate jdbcTemplate =
(JdbcTemplate) applicationContext.getBean("jdbcTemplate");
//测试
Long accountNum = jdbcTemplate.queryForObject
("select count(*) from account", Long.class);
System.out.println(accountNum);
}
JdbcTemplate小结:
①导入Spring-jdbc和spring-tx坐标
②创建数据库表和实体
③创建jdbcTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate()
jdbcTemplate. setDataSoure(dataSource)
④执行数据操作
更新操作:
jdbcTemplate.quate(sql.params)
查询操作:
jdbc.Template.query(sql,Mapper,params)
jdbc.Template.queryForObject(sql,Mapper,params)
之前所用的都是配置文件的方法,比较的麻烦,因此Spring提供也一种注解的方法来简化开发。
Spring是轻代码而配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。
spring原始注解主要是替代
常见的配置注解
注意:使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
参数问题:一般注解参数一般使用value表示id,但是Resource是用name表示id
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
非自定义的Bean的配置:
加载properies文件的配置:
组件扫描的配置:
引入其他文件:
在测试类中,每个方法都有以下两行
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml")
IAccountService as = ac.getBean("accountService",IAccountService.class);
这两行代码的作用是容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。
解决方法
①让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它
②将需要进行测试Bean直接在测试类中进行注入
Spring集成JUnit步骤
①导入Spring集成Junit的坐标
②使用@RunWith注解替换原来的运行期
③使用@ContextConfiguration指定配置文件或配置类
④使用@Autowired注入需要测试的对象
⑤创建测试方法进行测试
文件注入:
@ContextConfiguration("classpath:applciation.Context.xml")
注解注入:
@ContextConfiguration(class={SpringConfiguration.class)
AOP为Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重复性、同时提高了开发的效率。
作用:在程序运行期间,不修改源码的情况下对方进行功能增强。
优势:减少重复代码,提高开发效率,并且便于维护
实际上,AOP的底层通过Spring提供的动态技术实现。在运行期间Spring通过动态代理技术的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用的方法,从而完成功能的增强。
采用的动态代理方法有两种
JDK代理:基于接口的动态代理技术
原理步骤:
①编写目标类接口
public interface TargetInterface {
public void method();
}
②编写目标类
public class Target implements TargetInterface{
@Override
public void method() {
System.out.println("Target Running");
}
}
③编写动态代理
Target target = new Target();
TargetInterface proxy = (TargetInterface)
Proxy.newProxyInstance(
//目标对象类加载器
target.getClass().getClassLoader(),
//目标对象相同的接口字节对象数组
target.getClass().getInterfaces(),
new InvocationHandler() {
//调用代理对象的任何方法,实际执行的都是invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//前置增强
System.out.println("前置代码增强");
Object invoke = method.invoke(target, args);//执行目标方法
//后置增强
System.out.println("后置代码增强");
return invoke;
}
}
);
基于父类的动态代理技术
原理步骤:
①编写目标类
public class Target {
public void save() {
System.out.println("save running...");
}
}
②编写动态代理
Target target = new Target();
//返回值就是动态生成的代理对象,基于cglib
//1,创建增强器
Enhancer enhancer = new Enhancer();
//2.设置父类(目标)
enhancer.setSuperclass(Target.class);
//3.设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method,
Object[] objects, MethodProxy methodProxy) throws Throwable {
//执行前置
System.out.println("前置增强代码");
Object invoke = method.invoke(target, args);
//执行后置
System.out.println("后置增强代码");
return invoke;
}
});
Spring的AOP实现底层就是对上面的动态代码的代码进行了封装,封装后我们只需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
AOP的相关术语:
①导入AOP相关坐标
由于aop中封装了aspectj,因此也要导入aspectj相关坐标
org.springframework
spring-context
5.0.5.RELEASE
org.aspectj
aspectjweaver
1.8.13
②创建目标接口和目标类(内部有切点)
public interface TargetInterface {
public void method();
}
public class Target implements TargetInterface{
@Override
public void method() {
System.out.println("Target Running");
}
}
③创建切面类(内部有增强方法)
public class Advice {
public void Before(){
System.out.println("前置增强方法");
}
}
④将目标类和切面类的对象创建权交给Spring
⑤在applicationContext.xml中配置织入关系
导入aop命名空间
xmlns:aop="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
配置切点表达式和前置增强的织入关系
表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
注意:
访问修饰符可以省略
返回值、包名、类名、方法名可以使用星号*代表任意
包名与类名之间一个点代表当前包下的类,两个点..表示当前包及其子包下的类
参数列表可以使用两个点..表示任意个数,任意类型的参数列表
第一行表示com.itheima.aop包下的Target类下的返回类型为void的method方法
第二行表示com.itheima.aop包下的Target类下的返回类型为void的所有方法
第三行表示com.itheima.aop包下的所用方法
第四行表示com.itheima.aop包下以及子包下的所有方法
第五行表示第一层目标下以及第二层目录下的所有方法
通知的配置语法:
当多个增强的切点表示式相同时,可以将切点表达式进行抽取,在增强使用pointcut-ref属性代替来引用抽取的切点表达式 ①创建目标接口和目标类(内部有切点) ②创建切面类(内部有增强方法) ③将目标类和切面类的对象创建权交给Spring ④在切面类中使用注解配置织入关系 ⑤在配置文件中开启组件扫描和AOP的自动代理 通知的配置语法:@通知注解(“切点表达式”) 同xml配置aop一样,我们将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在增强注解中进行引用,具体如下: PlatformTransactionManager接口是Spring的事务管理器,它里面提供了我们常用的操作事务的方法。 注意: platformTransactionManager是接口类型,不同的DAO层技术则有不同的实现类。 例如: DAO层技术是jdbc或mybatis时: org.springframework.jdbc.datasource.DataSourceTransactionManager DAO层技术是hibernate时: org.springframework.ormhibernate5.HibernateTransactionManager TransactionDefinition是事务的定义信息对象,里面有如下方法: 事务隔离级别 设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读 事务传播行为 TransactionStatus接口提供的事务具体的运行状态,方法介绍如下: Spring的声明式事务顾名思义就是采用声明的方法来处理事务。这里所说的声明,就是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务。 事务管理不侵入开发的组件,具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分。如果想要改变事务管理策划的话。也只需要在定义中重新配置即可。 在不需要事务管理的时候,只要在设立文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便。 声明式申明控制明确事项: 谁是切点? 谁是通知? 配置切面? ①引入tx空间 ②配置事务增强 ③配置事务 AOP 织入 其中, ①编写dao ②编写service ③编写applicationContext.xml配置文件 ①使用@Transactional在需要进行事务控制的类或方法上修饰,注解可用的属性同xml配置方式,例如隔离级别、传播行为等。 ②注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置 ③使用在方法上,不同的方法可以采用不同的事务参数配置 ④xml配置文件中要开启事务的注解驱动
名称
标签
说明
前端通知
用于前置通知,指定增强的方法切入点之前执行
后置通知
用于配置后置通知,指定增强在切入点方法之后执行
环绕通知
用于配置环绕通知。指定增强的方法在切点之前和之后都执行
异常抛出通知
用于配置异常抛出通知,指定增强的方法出现异常时执行
最终通知
用于配置最终通知,无论增强方法执行是否有异常都会执行
基于注解的AOP开发
开发步骤
//定义目标接口
public interface TargetInterface {
public void method();
}
//定义实现类
public class Target implements TargetInterface {
@Override
public void method() {
System.out.println("Target running....");
}
}
public class MyAspect {
//前置增强方法
public void before(){
System.out.println("前置代码增强.....");
}
}
@Component("target")
public class Target implements TargetInterface {
@Override
public void method() {
System.out.println("Target running....");
}
}
@Component("myAspect")
public class MyAspect {
public void before(){
System.out.println("前置代码增强.....");
}
}
@Component("myAspect")
@Aspect
public class MyAspect {
@Before("execution(* com.itheima.aop.*.*(..))")
public void before(){
System.out.println("前置代码增强.....");
}
}
注解通知的类型
名称
注解
说明
前置通知
@Before
用于配置前置通知,指定增强的方法在切入点方法之前执行
后置通知
@AfterReturning
用于配置后置通知,指定增强的方法在切入点方法之后执行
环绕通知
@Around
用于配置通知。指定增强的方法在切入点方法之前和之后都执行
异常抛出通知
@AfterThrowing
用于配置异常抛出通知。指定增强的方法在出现异常进行。
最终通知
@After
用于配置最终通知,无论增强方法执行是否有异常都会执行
切点表达式的抽取
@@Component("myAspect")
@Aspect
public class MyAspect {
@Before("MyAspect.myPoint()")
public void before(){
System.out.println("前置代码增强.....");
}
@Pointcut("execution(* com.itheima.aop.*.*(..))")
public void myPoint(){}
}
Spring的事务控制
编程式事务控制相关对象
PlatformTransactionManager
TransactionDefinition
TransactionStatus
基于XML的声明式事务控制
定义
声明式事务处理的作用
声明式事务控制的实现
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
基于注解的声明式事务控制
使用注解配置声明式事务控制
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void out(String outMan, double money) {
jdbcTemplate.update("update account set money=money-?
where name=?",money,outMan);
}
public void in(String inMan, double money) {
jdbcTemplate.update("update account set money=money+?
where name=?",money,inMan);
}
}
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Transactional(isolation = Isolation.REPEATABLE_READ,propagation =
Propagation.REQUIRED)
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
int i = 1/0;
accountDao.in(inMan,money);
}
}
注解配置声明式事务控制解析