Spring5
Spring 是于2003年兴起的一款轻量级的,非侵入式的IOC和AOP的一站式的java开发框架,为简化企业级应用开发而生
Spring有两个核心部分:IOC 和 AOP
- IOC:控制反转,把创建对象过程交给 Spring 进行管理
- AOP:面向切面,不修改源代码进行功能增强
Spring特点:
- 方便解耦,简化开发
- Aop 编程支持
- 方便程序测试
- 方便和其他框架进行整合
- 方便进行事务操作
- 降低 API 开发难度
IOC容器
定义
控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
目的:降低耦合度
IOC基于IOC容器完成,IOC容器底层就是对象工厂
Spring提供IOC容器实现两种方式(两个接口):
BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用,其加载配置文件时不会创建对象,在获取对象(使用)才去创建对象
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用,其加载配置文件时会把配置文件对象进行创建
Bean
概念
Bean是Spring装配的组件模型,一切实体类都可以配置成一个Bean,进而就可以在任何其他的Bean中使用,一个Bean也可以不是指定的实体类,这就是抽象Bean
作用
- 用于配置对象让Spring来创建
- 默认情况下调用类中的无参构造函数,如果没有无参构造函数则无法创建
属性
- id: 给对象在容器中提供一个唯一标识,用于获取对象
- class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数
- scope:指定对象的作用范围
- singleton:默认值,单例的
- prototype:多例的
- request:WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中
- session:WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中
- global session:WEB项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession相当于session
Bean管理
IOC操作Bean管理就是两个操作:
- Spring创建对象
- Spring注入属性
基于XML方式注入属性(DI:依赖注入(注入属性)):
-
set方法注入
@Test public void testAdd(){ //1.加载spring配置文件 BeanFactory context= new ClassPathXmlApplicationContext("bean2.xml"); //2.获取配置创建的对象 Book book = context.getBean("book", Book.class); System.out.println(book); book.add(); }
<!--set方法注入--> <bean id="book" class="com.lanest.Book"> <property name="name" value="java教程"/> <property name="author" value="lanest"/> </bean>
-
有参构造注入
<!--有参构造注入--> <bean id="user" class="com.lanest.User"> <constructor-arg name="id" value="10"/> <constructor-arg name="name" value="lanest"/> </bean>
-
p名称空间注入
<!--p名称空间注入--> <bean id="book2" class="com.lanest.Book" p:name="English" p:author="jack"/>
-
注入空值和特殊符号
<!--注入空值和特殊符号--> <bean id="book3" class="com.lanest.Book"> <property name="author"> <null/> </property> <!--特殊符号赋值--> <!--属性值包含特殊符号 a 把<>进行转义 < > b 把带特殊符号内容写到CDATA --> <property name="name"> <value><![CDATA[<<广州>>]]></value> </property> </bean>
-
注入属性-外部bean
<!--注入属性-外部bean--> <bean id="userService" class="com.lanest.UserService"> <property name="userDao" ref="userDaoImpl"/> </bean> <bean id="userDaoImpl" class="com.lanest.UserDaoImpl"> </bean>
-
注入属性-内部bean
<!--注入属性-内部bean--> <bean id="emp" class="com.lanest.Emp"> <!--设置两个普通属性--> <property name="ename" value="Andy"></property> <property name="gender" value="女"></property> <property name="dept"> <bean id="dept" class="com.lanest.Dept"> <property name="dname" value="研发部门"></property> </bean> </property> </bean>
-
级联赋值
<!--级联赋值 方式一:--> <bean id="emp3" class="com.lanest.Emp"> <!--设置两个普通属性--> <property name="ename" value="Andy"/> <property name="gender" value="女"/> <!--级联赋值--> <property name="dept" ref="dept4"/> </bean> <bean id="dept4" class="com.lanest.Dept"> <property name="dname" value="公关部门"/> </bean>
<!--级联赋值 方式二:--> <bean id="emp2" class="com.lanest.Emp"> <!--设置两个普通属性--> <property name="ename" value="jams"></property> <property name="gender" value="男"></property> <!--级联赋值--> <property name="dept" ref="dept2"></property> <property name="dept.dname" value="技术部门"></property> </bean> <bean id="dept2" class="com.lanest.Dept"> </bean>
-
注入集合类型属性
<!--注入集合类型属性--> <bean id="stu" class="com.lanest.Stu"> <!--数组类型属性注入--> <property name="courses"> <array> <value>java课程</value> <value>数据库课程</value> </array> </property> <!--list类型属性注入--> <property name="list"> <list> <value>张三</value> <value>小三</value> </list> </property> <!--map类型属性注入--> <property name="maps"> <map> <entry key="JAVA" value="java"/> <entry key="PHP" value="php"/> </map> </property> <!--set类型属性注入--> <property name="sets"> <set> <value>MySQL</value> <value>Redis</value> </set> </property> <!--注入list集合类型,值是对象--> <property name="courseList"> <list> <ref bean="course1"/> <ref bean="course2"/> </list> </property> </bean>
-
自动装配:根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值进行装配
bean标签属性autowire,配置自动装配
常用两个值:
byName 根据属性名称注入,注入值bean的id值和类的属性名称一样
byType 根据属性类型注入
<!--自动装配-->
<bean id="emp" class="com.lanest.entity.Emp" autowire="byType">
</bean>
基于注解方式:
注解:是代码的特殊标记
- 格式:@注解名称(属性名称=属性值,属性名称=属性值…)
- 使用注解,注解作用在类上面,方法上面,属性上面
- 作用:简化xml配置
Spring针对Bean管理中创建对象提供注解:
- @Componet:普通组件
- @Service:业务逻辑层组件
- @Controller:表述层控制器组件
- @Repository:持久化层组件
上面四个注解功能是一样的,都可以用来创建bean实例,只是仅仅为了让开发人员自己明确当前组件扮演的角色
基于注解方式实现对象创建:
-
引入依赖
-
开启组件扫描
<context:componet-scan base-package="com.lanest"></context>
相当于springboot中的@SpringbootApplication注解中的@ComponentScan注解
-
创建类,添加注解
//value属性值可以省略不写,默认值时类名称,首字母小写 @Component(value = "userService2") //此注解等于xml配置文件 <bean id="userService" class=".."/> public class UserService2 { public void add(){ System.out.println("service add方法..."); } }
开启组件扫描配置:
<!--开启组件扫描配置-->
<!--示例 1
use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter
context:include-filter ,设置扫描哪些内容
-->
<context:component-scan base-package="com.lanest" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/><!--代表只扫描Controller注解的类-->
</context:component-scan>
<!--示例 2
下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.lanest">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/><!--表示Controller注解的类之外一切都进行扫描-->
</context:component-scan>
基于注解方式实现属性注入:
-
@AutoWired:根据属性类型进行自动装配
@Service public class UserService3{ //定义dao类型属性 //不需要添加set方法 //添加注入属性注解 @Autowired //根据属性类型进行自动装配 private UserDao userDao; }
//@Repository(value = "userDaoImpl") 默认值 @Repository public class UserDaoImpl implements UserDao {...}
-
@Qualifier:根据属性名称进行注入,需要和@Autowired一起使用,如果有多个实现类,@AutoWired则不知道装配哪个,此时可以用@Qualifier
@Autowired //根据属性类型进行自动装配 @Qualifier(value = "userDaoImpl") //区别同一接口下的多个实现类 private UserDao userDao;
-
@Resource:可以根据类型,也可以根据名称注入(属于javax包里面的,不是spring包,不推荐使用)
//@Resource 根据类型进行注入 @Resource(name = "userDaoImpl") //根据名称进行注入 private UserDao userDao;
-
@Value:注入普通类型属性
@Value(value = "算法设计") private String cname;
完全注解开发
@Configuration 作为配置类,替代xml文件
@Configuration //此注解作为配置类,替代xml文件
@ComponentScan(basePackages = "com.lanest") //组件扫描
public class SpringConfig {
}
工厂Bean
Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
-
普通 bean:在配置文件中定义 bean 类型就是返回类型
-
工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
实现步骤:
-
第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
-
第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
public class FactoryBeanTest implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("aaa");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
<bean id="factoryBeanTest" class="com.lanest.test.FactoryBeanTest">
</bean>
@Test
public void testFactoryBean(){
BeanFactory context= new ClassPathXmlApplicationContext("bean1.xml");
Course course = context.getBean("factoryBeanTest", Course.class);
//返回值类型可以不是定义的bean类型
System.out.println(course);
}
作用域
spring默认情况下,bean是单实例对象
作用域设置:
-
xml中bean标签里面有属性scope用于设置单实例和多实例
-
scope属性值默认值为singleton,表示单实例对象
-
singleton 单实例,prototype 多实例
-
设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象 ;
设置 scope 值是 prototype 时候,并不是在加载 spring 配置文件时候创建对象,而是在调用 getBean 方法的时候创建多实例对象
-
<bean id="book6" class="com.lanest.entity.Book" scope="prototype"><!--设置为多实例-->
<property name="list" ref="bookList"/>
</bean>
生命周期
生命周期是指从对象创建到对象销毁的过程
bean的生命周期:
- 通过构造器创建bean实例(无参构造)
- 为bean的属性设置值和对其他bean引用(调用set方法)
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- bean可以使用了(对象获取到了)
- 当容器关闭时,调用bean的销毁的方法(需要进行配置销毁的方法)
bean 的后置处理器,bean 生命周期有七步: (正常生命周期为五步,而配置后置处理器后为七步)
-
通过构造器创建 bean 实例(无参数构造)
-
为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
-
把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
-
调用 bean 的初始化的方法(需要进行配置初始化的方法)
-
把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
-
bean 可以使用了(对象获取到了)
-
当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
<!--配置文件的bean参数配置-->
<bean id="orders" class="com.lanest.entity.Orders" init-method="initMethod" destroy-method="destroyMethod"> <!--配置初始化方法和销毁方法-->
<property name="oname" value="平板"/><!--这里就是通过set方式(注入属性)赋值-->
</bean>
public class Orders {
private String oname;
//无参数构造
public Orders() {
System.out.println("第一步:执行无参数构造创建 bean 实例");
}
//调用set方法
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步:调用 set 方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步:执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步:执行销毁的方法");
}
}
后置处理器实现:
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.lanest.test.MyBeanPost"></bean>
/**
* @Author: Lanest
* @Date: 2023-09-08
* @Description: 创建后置处理器实现类
*/
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化 之前 执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化 之后 执行的方法");
return bean;
}
}
AOP
概念
面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
简单来说,就是不通过修改源代码方式,在干功能里面添加新功能
比如在登录功能上添加权限判断功能
底层原理
AOP底层使用动态代理,动态代理有两种情况:
-
有接口情况,即基于接口的动态代理,使用 JDK 动态代理 ;创建接口实现类代理对象,增强类的方法
-
没有接口情况,即基于类的动态代理,使用 CGLIB 动态代理;创建子类的代理对象,增强类的方法
JDK动态代理
使用JDK动态代理,可以调用Proxy类里面的newProxyInstance方法实现:
- 参数一:类加载器
- 参数二:增强方法所在的类,这个类实现的接口(支持多个接口)
- 参数三:实现接口InvocationHandler,创建代理对象,写增强的部分
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h) {...}
具体实现:
public interface UserDao {
public int add(int a,int b);
}
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
System.out.println("add方法执行...");
return a+b;
}
}
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
/**
* 参数一:类加载器
* 参数二:增强方法所在的类,这个类实现的接口(支持多个接口)
* 参数三:实现接口InvocationHandler,创建代理对象,写增强的部分
*/
UserDao dao =(UserDao)Proxy.newProxyInstance
(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result:" + result);
}
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
//1 把创建的是谁的代理对象,把谁传递过来
//有参数构造传递
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args));
//被增强的方法执行
Object res = method.invoke(obj, args);
//方法之后
System.out.println("方法之后执行...."+obj);
return res;
}
}
操作术语
-
连接点:类里面可以被增强的方法
-
切入点:实际被真正增强的方法
-
通知(增强):实际增强的逻辑部分称为通知(增强)
有五种类型:
- 前置通知:增强方法之前执行的通知
- 后置通知:增强方法之后执行的通知。
- 环绕通知:增强方法之后执行的通知。
- 异常通知:增强方法之后执行的通知。
- 最终通知:类似
try-catch-finally
中的finally
,无论是否出异常,最终都会执行的通知
-
切面:把通知应用到切入点的过程,是个动作
AOP操作
Spring框架一般都是基于AspectJ实现AOP操作
AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring一起使用进行AOP操作
切入点表达式:execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表])
1.对 com.atguigu.dao.BookDao 类里面的 add 进行增强:
execution(* com.lanest.dao.BookDao.add(...))
2.对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强:
execution(* com.lanest.dao.BookDao.* (...))
3.对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强:
execution(* com.lanest.dao.*.* (...))
基于AspectJ实现AOP操作:
-
基于xml配置文件实现
<bean id="book" class="com.lanest.aop.xml.Book"/> <bean id="bookProxy" class="com.lanest.aop.xml.BookProxy"/> <!--配置 aop 增强--> <aop:config> <!--切入点--> <aop:pointcut id="p" expression="execution(* com.lanest.aop.xml.Book.buy(..))"/> <!--配置切面--> <aop:aspect ref="bookProxy"> <!--增强作用在具体的方法上--> <aop:before method="before" pointcut-ref="p"/> </aop:aspect> </aop:config>
-
基于注解方式实现
@Component public class User { public void add() { System.out.println("add......."); } }
@Component @Aspect //生成代理对象 public class UserProxy { //前置通知 @Before(value = "execution(* com.lanest.aop.anno.User.add(..))") public void before() { System.out.println("before......"); } //最终通知 @After(value = "execution(* com.lanest.aop.anno.User.add(..))") public void after() { System.out.println("after......"); } //后置通知 @AfterReturning(value = "execution(* com.lanest.aop.anno.User.add(..))") public void afterReturning() { System.out.println("afterReturning......"); } //异常通知 @AfterThrowing(value = "execution(* com.lanest.aop.anno.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing......"); } //环绕通知 @Around(value = "execution(* com.lanest.aop.anno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ System.out.println("around之前......"); proceedingJoinPoint.proceed(); //切入点执行 System.out.println("around之后......"); } }
<!-- 开启注解扫描 --> <context:component-scan base-package="com.lanest.aop.anno"/> <!-- 开启Aspect生成代理对象--> <aop:aspectj-autoproxy/>
@AspectJ注解:
@Before:前置通知
@AfterReturning:后置通知,在返回结果后执行,有异常不执行
@Around:环绕通知,在方法之前和之后都执行
@AfterThrowing:异常通知,方法有异常才执行
@After:最终通知,方法之后就执行
设置增强类的优先级:
在增强类上面添加注解@Order(数字类型值),值越小优先级越高
@Component
@Aspect
@Order(1)
public class UserProxy{...}
事务
概念
事务是数据库操作最基本单元,事务由单独单元的一个或多个SQL语句组成,在这个单元中,每个SQL语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条SQL语句一旦执行失败或产生错误,整个单元将会回滚。所有受到影响的数据将返回到事物开始以前的状态;如果单元中的所有SQL语句均执行成功,则事物被顺利执行
ACID
事务的ACID属性:
- 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生 - 一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态 - 隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个事务请求同一数据。不同的事务之间彼此没有任何干扰。 - 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
声明式事务管理
事务添加到JavaEE三层结构里的Service层
在Spring进行事务管理操作有两种方式:
-
编程式事务管理
-
声明式事务管理(使用这个):底层使用AOP原理,对方法前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完目标方法之后根据执行情况提交或回滚事务
-
基于注解方式
-
基于xml方式
-
Spring事务管理API
提供一个接口PlatformTransactionManager
,代表事务管理器,此接口针对不同的框架提供不同的实现类
基于注解方式
-
开启事务注解
<!--开启注解扫描--> <context:component-scan base-package="com.lanest"/> <!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 数据库连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${prop.url}" /> <property name="username" value="${prop.username}" /> <property name="password" value="${prop.password}" /> <property name="driverClassName" value="${prop.driverClass}" /> </bean> <!--JdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入上面的dataSource--> <property name="dataSource" ref="dataSource"/> </bean> <!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"/> </bean> <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"/>
-
类上面添加事务注解
@Transactional
@Service @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, timeout = 2, readOnly = true, rollbackFor = ArithmeticException.class) public class UserService {...}
参数配置
注解@Transactional
参数配置:
-
propagation:事务传播行为
在spring中有7种 :
-
**REQUIRED:**如果有事务在运行,当前的方法就在这个事务内运行,否则就启动一个新的事务,并在自己的事务内运行
如:如果add方法本身有事务,调用update方法后,update使用add方法里面的事务;如果add方法本身没有事务,调用update方法后,创建新事物
-
**REQUIRED_NEW:**当前的方法必须启动新事物,并在它自己的事务内运行,如果有事务内运行,如果有事务正在运行,应该将它挂起
如:使用add方法调用update方法,无论add方法是否有事务,都创建新事务
-
**SUPPORTS:**如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务种
-
NOT_SUPPORTS:当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
-
MANDATORT:当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常
-
NEVER:当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
-
NESTED:如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则就启动一个新的事务,并在它自己的事务内运行
-
-
isolation:事务隔离级别
事务的隔离性,多事务操作之间不会产生影响
如果不考虑隔离性,有三个读问题:
-
脏读:一个未提交事务读取到另一个未提交事务的数据
-
不可重复读:一个未提交事务读取到另一个提交事务修改数据
-
虚(幻)读:一个未提交事务读取到另一个提交事务添加数据
通过设置事务隔离级别,解决读问题:
-
-
timeout:超时时间
事务超过超时时间还没提交则进行回滚,默认值是-1,以秒为单位
-
readOnly:是否只读
默认false
-
rollbackFor:回滚
设置出现哪些异常进行事务回滚
-
rollbackForClassName:回滚
设置出现哪些异常名称进行事务回滚
-
noRollbackFor:不回滚
设置出现哪些异常不进行事务回滚
-
noRollbackForClassName:不回滚
设置出现哪些异常名称不进行事务回滚
完全注解方式
@Bean注解:(等同于xml中的bean标签)创建一个bean对象,并交给Spring管理,Spring将这个bean对象放入IOC容器,这些bean都要在**@Configuration**注解下的类创建
用配置类代替xml配置文件:
@Configuration
@ComponentScan(basePackages = {"com.lanest"})//开启注解扫描
@EnableTransactionManagement //开启事务
public class MyConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() throws IOException {
//用类加载器读取配置文件中的4个基本信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
//创建属性集合类,用于载入配置文件的属性数据
Properties p = new Properties();
p.load(is);
//获取配置文件中的值
String username = p.getProperty("prop.username");
String password = p.getProperty("prop.password");
String url = p.getProperty("prop.url");
String driverClass = p.getProperty("prop.driverClass");
//创建德鲁伊数据库连接池
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) { //到IOC容器中根据类型找到dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource); //注入dataSource
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) { //到IOC容器中根据类型找到dataSource
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
基于xml方式
- 配置事务管理器
- 配置通知
- 配置切入点和切面
<!--开启注解扫描-->
<context:component-scan base-package="com.lanest"/>
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${prop.url}" />
<property name="username" value="${prop.username}" />
<property name="password" value="${prop.password}" />
<property name="driverClassName" value="${prop.driverClass}" />
</bean>
<!--JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入上面的dataSource-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--声明式事务-->
<!--1、创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--2、配置通知-->
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--name指定在哪个方法上面添加事务-->
<tx:method name="transfer" propagation="REQUIRED" isolation="REPEATABLE_READ"/>
<!--也可以通过这种规则决定哪个方法上面添加事务<tx:method name="trans*"/>-->
</tx:attributes>
</tx:advice>
<!--3、配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.lanest.transaction.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
Spring5新特性
-
基于java8,运行时兼容JDK9,删除了很多不建议使用的方法和类
-
移除了Log4jConfigListener,而使用Log4j2
-
支持**@Nullable**注解:用在方法、属性、参数上面,表示方法或属性值或参数值可以为空
-
引入了Junit5、@Test注解
-
Webflux:类似于SpringMVC,针对响应式编程,但SpringMVC是命令式编程,Webflux是异步响应式编程
**响应式编程:**一种面向数据流和变化传播的编程范式,这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播
异步: 调用者发送请求,如果发送请求之后不等着对方回应就去做其他事情就是异步
非阻塞: 被调用者受到请求之后,受到请求之后马上给出反馈然后再去做事情就是非阻塞
Spring6新特性
- 整个框架的代码基于Java 17源码级别。
- Servlet、JPA等从"javax"迁移到"jakata"命名空间。
- 兼容最新一代的web容器:Tomcat 10,Jetty 11.
- 升级到ASM 9.4和Kotlin 1.7
- 移除过时的Tiles和FreeMarker JSP的支持
- JDK HttpClient与WebClient 集成