Spring初级入门
文章目录
Spring简介
- Spring是分层的 Java SE/EE应用 full-stack(全栈式) 轻量级开源框架。
- 提供了表现层 (SpringMVC)、持久层(Spring JDBC Template)以及业务层事务管理等应用技术。也能整合开源世界众多著名的第三方框架。
- 两大核心思想: IOC( Inverse Of Control : 控制反转 ) 和 AOP( Aspect Oriented Programming : 面向切面编程 )
Spring优势
-
方便解耦,简化开发
Spring就是一个容器,可以将对象的创建和关系维护交给Srping管理
-
AOP编程的支持
Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能
-
声明式事务的支持
通过配置完成事务的管理,无需手动编程
-
方便测试,降低JAVAEE API的使用
Spring对Junit4支持,可以使用注解测试
-
方便集成各种优秀框架
不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持
IOC
IOC即控制反转( Inverse Of Control )是一种思想。指导我们设计更加松耦合的程序。
-
控制:在java中指的是对象的控制权限(创建、销毁)
-
反转:指的是原先由开发者在类中手动控制反转到由Spring容器控制
自定义IOC容器
- 创建java项目,导入自定义IOC相关坐标
<!--解析xml坐标-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<!--单元测试坐标-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
- 编写Dao接口和实现类
- 编写Service接口和实现类
- 编写beans.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="userDao" class="com.hezhe.dao.impl.UserDaoImpl"></bean>
</beans>
- 编写BeanFactory工具类-----暂时代替Spring容器
public class BeanFactory {
private static Map<String, Object> ioc = new HashMap<>();
// 程序启动时,初始化对象实例
static {
try {
// 1.读取配置文件
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
// 2.解析xml
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(in);
// 3.编写xpath表达式
String xpath = "//bean";
// 4.获取所有的bean标签
List<Element> list = document.selectNodes(xpath);
// 5.遍历并创建对象实例,设置到map集合中
for (Element element : list) {
String id = element.attributeValue("id");
String className = element.attributeValue("class");
Object object = Class.forName(className).newInstance();
ioc.put(id, object);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取指定id的对象实例
public static Object getBean(String beandId) {
return ioc.get(beandId);
}
}
- 修改UserServiceImpl实现类,通过 BeanFactory 来获取对应的dao对象
使用Spring的IOC
- 创建java项目,导入spring开发基本坐标
<!--spring坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
-
编写Dao接口和实现类
-
创建spring核心配置文件 ( 通常为:applicationContext.xml )
<?xml version="1.0" encoding="UTF-8"?>
<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
<beans ...>
<bean id="userDao" class="com.hezhe.dao.impl.UserDaoImpl"></bean>
</beans>
- 使用spring相关API获得Bean实例
public class UserTest {
@Test
public void testSave() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
}
Spring相关API
Spring的API体系异常庞大,目前只关注 BeanFactory 和 ApplicationContext 即可
- BeanFactory:是IOC容器的核心接口,它定义了IOC的基本功能
- 特点:懒汉模式,只有调用getBean的时候才会去创建实例
特点:在第一次调用 getBean() 方法时,创建指定对象实例
- ApplicationContext:代表应用上下文对象,可以获取spring中IOC容器的Bean对象
- 特点:饿汉模式,启动spring容器就会创建实例
特点:在Spring容器启动时,加载并创建所有对象的实例
常用实现类
-
ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件 推荐使用这种。
-
FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
-
AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
常用方法
//1.根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。
Object getBean(String name);
//2.根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错。
<T> T getBean(Class<T> requiredType);
//3.根据Bean的id和类型获得Bean实例,解决容器中相同类型Bean有多个情况。
<T> T getBean(String name,Class<T> requiredType);
Spring配置文件
- Bean标签基本配置
<bean id="" class=""></bean>
* 用于配置对象交由Spring来创建。
* 基本属性:
id:Bean实例在Spring容器中的唯一标识
class:Bean的全限定名
* 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功。
- Bean标签范围配置
<bean id="" class="" scope=""></bean>
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中 |
session | WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中 |
globalsession | WEB项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession 相当于 session |
-
当scope为singleton时
实例化个数:1个
实例化时机:当spring核心配置文件被加载时
生命周期:
对象创建:当应用加载,创建容器时,对象就被创建了
对象运行:只要容器在,对象就一直活着
对象销毁:当应用卸载,销毁容器时,对象就被销毁了
-
当scope为singleton时
实例化个数:多个
实例化时机:当调用getBean()方法时实例化Bean
生命周期:
对象创建:当使用对象时,创建新的对象实例
对象运行:只要对象使用中,对象就一直活着
对象销毁:当对象长时间不用时,被Java的垃圾回收机制回收了
- Bean生命周期配置
<bean id="" class="" scope="" init-method="" destroy-method=""></bean>
* init-method:指定类中的初始化方法名称
* destroy-method:指定类中销毁方法名称
- Bean实例化三种方式
- 无参构造方法实例化,默认方法
- 工厂静态方法实例
<!--
依赖的jar包中有个A类,A类中有个静态方法m1,m1方法的返回值是一个B对象。如果我们频繁使用B对象,此时我们可以将B对象的创建权交给spring的IOC容器,以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得。
-->
<bean id="userDao" class="com.hezhe.factory.StaticFactoryBean" factory-method="createUserDao" />
- 工厂普通方法实例化
<!--
依赖的jar包中有个A类,A类中有个普通方法m1,m1方法的返回值是一个B对象。如果我们频繁使用B对象,此时我们可以将B对象的创建权交给spring的IOC容器,以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得。
-->
<bean id="dynamicFactoryBean" class="com.hezhe.factory.DynamicFactoryBean"/>
<bean id="userDao" factory-bean="dynamicFactoryBean" factorymethod="createUserDao"/>
Bean依赖注入概述
依赖注入 DI (Dependency Injection ) : 它是Spring框架核心IOC的具体实现。
IOC解耦并不是消除依赖关系,而是降低依赖关系,将业务层和持久层的依赖关系由Spring来维护。
依赖注入的方式
- 构造方法 bean + constructor-arg
- set方法 bean + property
- P命名空间 本质是set方法注入,简化set配置
<!--构造方法-->
<bean id="" class="">
<constructor-arg name="" ref=""/>
</bean>
<!--set方法-->
<bean id="" class="">
<property name="" ref=""/>
</bean>
<!--P命名空间-->
<!--先引入约束
xmlns:p="http://www.springframework.org/schema/p"
-->
<bean id="" class="" p:userDao-ref=""></bean>
Bean依赖注入的数据类型
注入的三种类型:
- 普通数据类型
- 引入数据类型
- 集合数据类型
注入普通数据类型
<!--实体类中写上普通数据类型属性并添加set方法-->
<bean id="" class="">
<property name="" value=""/>
<property name="" value=""/>
</bean>
注入集合数据类型
<!--list集合-->
<bean id="" class="">
<property name="list">
<list>
<!--list中基本数据类型-->
<value></value>
<!--list中引入数据类型-->
<rel bean=""></rel>
</list>
</property>
</bean>
<!--Set集合:将list集合中的 name 改为set-->
<!--Array集合-->
<bean id="" class="">
<property name="list">
<array>
<!--list中基本数据类型-->
<value></value>
<!--list中引入数据类型-->
<rel bean=""></rel>
</array>
</property>
</bean>
<!--Map集合-->
<bean id="" class="">
<property name="map">
<map>
<!--map中value为基本数据类型-->
<entry key="" value=""/>
<!--map中value为引入数据类型-->
<entry key="" value-ref=""/>
</map>
</property>
</bean>
<!--Properties配置-->
<bean id="" class="">
<property name="properties">
<props>
<prop key="k1">value1</prop>
<prop key="k2">value2</prop>
<prop key="k3">value3</prop>
</props>
</property>
</bean>
配置文件模块化
当Spring’配置项过多时,可将部分配置拆解到其他配置文件中
- 并列的多个配置文件
ApplicationContext act = new ClassPathXmlApplicationContext("bean1,xml","bean2.xml","",...);
- 主从配置文件
<import resource="applicationContext-xxx.xml"/>
注意事项
- 同一个xml中不能出现相同名称的bean,如果出现会报错
- 多个xml如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean
数据库连接配置
<!--
命名空间
xmlns:context="http://www.springframework.org/schema/context"
约束路径
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
-->
<!--引入外部配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置数据库资源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--使用xml中的el表达式获取配置文件参数-->
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
Spring注解开发
代替bean标签
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用,根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestory | 使用在方法上标注该方法是Bean的销毁方法 |
注意1:JDK11以后完全移除了javax扩展,导致无法使用@Resource注解,需要引入依赖
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
注意2:若使用注解开发,需要在核心配置文件中配置需要扫描识别注解的范围
<!--注解的组件扫描-->
<context:component-scan base-package="com.hezhe"></context:component-scan>
核心配置文件注解
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个Spring 配置类,当创建容器时会从该类上加载注解 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载 properties 文件中的配置 |
@ComponentScan | 用于指定 Spring 在初始化容器时要扫描的包 |
@Import | 用于导入其他配置类 |
对应案例
//核心配置类
@Configuration
@ComponentScan("com.hezhe")
@Import(DataSourceConfig.class)
public class SpringConfig {
@Bean("queryRunner")
public QueryRunner getQueryRunner(@Autowired DataSource dataSource) {
return new QueryRunner(dataSource);
}
}
//数据库配置类
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
//加载配置类
ApplicationContext act = AnnotationConfigApplicationContext(SpringConfig.class);
Spring整合Junit
普通Junit测试问题:在普通的测试类中,需要开发者手动加载配置文件并创建Spring容器,然后通过Spring相关API获得Bean实例;如果不这么做,那么无法从容器中获得对象。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
XxxService xxxService = applicationContext.getBean(XxxService.class);
让SpringJunit负责创建Spring容器来简化这个操作
相关步骤如下:
- 导入spring集成Junit的坐标
<!--此处需要注意的是,spring5 及以上版本要求 junit 的版本必须是 4.12 及以上-->
<!--单元测试坐标-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring集成Junit的坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
- 使用@Runwith注解替换原来的运行器
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunitTest {
}
- 使用@ContextConfiguration指定配置文件或配置类
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value = {"classpath:applicationContext.xml"}) 加载spring核心配置文件
@ContextConfiguration(classes = {SpringConfig.class}) // 加载spring核心配置类
public class SpringJunitTest {
}
- 即可使用@Autowired注入Bean对象
AOP
传统事务
需构建数据库连接线程工具类、事务管理类,在service层对具体方法编写相关的事务代码。
这时候的业务代码和事务代码混在一起,并且多次使用事务会不停重复编写相同的事务代码,显得额外臃肿。
Proxy动态代理
常用代理技术
- JDK代理
基于接口的动态代理技术·:利用拦截器(必须实现invocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强
- CGLIB代理
基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行增强
AOP简介
AOP(Aspect Oriented Programming)面向切面编程
AOP是OOP的延续,利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分的耦合度降低,提高程序的可重用性,同时提高开发效率。
优势:
- 在程序运行期间,在不修改源码的情况下对方法进行功能增强
- 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
- 减少重复代码,提高开发效率,便于后期维护
AOP底层实现
AOP底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
AOP的相关术语
概念 | 解释 |
---|---|
Target(目标对象) | 代理的目标对象 |
Proxy (代理) | 一个类被 AOP 织入增强后,就产生一个结果代理类 |
Joinpoint(连接点) | 可能被增强的方法 |
Pointcut(切入点) | 需要增强的方法 |
Advice(通知/ 增强) | 封装增强业务逻辑的方法 分类:前置、后置、异常、最终、环绕 |
Aspect(切面) | 切点+通知 |
Weaving(织入) | 将切点与通知结合,产生代理对象的过程 |
AOP开发明确事项
- 开发阶段
- 编写核心业务代码(目标类的目标方法) 切入点
- 把公用代码抽取出来,制作成通知(增强功能方法) 通知
- 在配置文件中,声明切入点与通知间的关系,即切面
- 运行阶段
Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
-
底层代理实现
在 Spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
- 当bean实现接口时,会用JDK代理模式
- 当bean没有实现接口,用cglib实现(可强制使用cglib,加上以下配置即可)
<aop:aspectj-autoproxy proxyt-target-class="true"/>
基础例子
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--目标类交给IOC容器-->
<bean id="target" class="com.*.service.impl.targetImpl"></bean>
<!--通知类交给IOC容器-->
<bean id="advice" class="com.*.advice.MyAdvice"></bean>
<aop:config>
<aop:aspect ref="advice">
<!--配置目标类的切点方法执行时,使用通知类的通知方法进行前置增强-->
<aop:before method="adviceName" pointcut="execution(* com.*.service.impl.targetImpl.funcName(..))"></aop:before>
</aop:aspect>
</aop:config>
</beans>
XML配置AOP详解
切点表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 访问修饰符可以省略
- 返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
- 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
- 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
execution(public void com.hezhe.service.impl.AccountServiceImpl.transfer())
execution(void com.hezhe.service.impl.AccountServiceImpl.*(..))
execution(* com.hezhe.service.impl.*.*(..))
execution(* com.hezhe.service..*.*(..))
切点表达式可以抽取
<aop:config>
<!--抽取的切点表达式-->
<aop:pointcut id="myPointcut" expression="execution(* com.*.service.impl.targetImpl.funcName(..))"> </aop:pointcut>
<aop:aspect ref="advice">
<aop:before method="adviceName" pointcut-ref="myPointcut"></aop:before>
</aop:aspect>
</aop:config>
通知类型
名称 | 标签 | 说明 |
---|---|---|
前置通知 | aop:before | 切入点方法之前执行 |
后置通知 | aop:afterReturning | 切入点方法之后执行 |
异常通知 | aop:afterThrowing | 出现异常后执行 |
最终通知 | aop:after | 是否有异常,都会执行 |
环绕通知 | aop:around | 手动控制增强代码在什么时候执行(独立使用) |
注解方式实现AOP
基础案例
@Component
@Aspect
public class MyAdvice{
@Pointcut("execution(* com.hezhe..*.*(..))")
public void myPoint(){}
@Before("MyAdice.myPoint()")
public void before(){
//前置通知的方法体
}
}
-------------------------------------------------------------------------
@Configuration
@ComponentScan("com.hezhe")
@EnableAspectJAutoProxy //替代 <aop:aspectj-autoproxy />
public class SpringConfig {
}
Spring的Jdbc Template
简介
JdbcTemplate是spring框架中提供的一个模板对象,是对原始繁琐的Jdbc API对象的简单封装。
核心对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);
核心方法
int update(); 执行增、删、改语句
List<T> query(); 查询多个
T queryForObject(); 查询一个
new BeanPropertyRowMapper<>(); 实现ORM映射封装
Spring的事务
编程式事务控制对象
Spring中的事务主要是通过控制三个API实现的
- PlatformTransactionManager 负责事务的管理,它是个接口,其子类负责具体工作
- TransactionDefinition 定义了事务的一些相关参数
- TransactionStatus 代表事务运行的一个实时状态
三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态。
基于XML的声明式事务控制
基础案例
<?xml version="1.0" encoding="UTF-8"?>
<!--1.引入tx命名空间-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--2.事务管理器通知配置-->
<!--注入spring提供的事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--声明式事务管理-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
</tx:attributes>
</tx:advice>
<!--3.事务管理器AOP配置-->
<aop:config>
<!--切点-->
<aop:pointcut id="myPointcut" expression="execution(* com.hezhe.service.serviceImpl.UserServiceImpl.transfer(..))"/>
<!--切面设置-->
<aop:advisor advice-ref="txAdvice"
pointcut-ref="myPointcut"></aop:advisor>
<!--通知设置-->
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="myPointcut"></aop:before>
</aop:aspect>
</aop:config>
</beans>
事务参数的配置
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
<!--
name : 切点方法名称
isolation : 事务隔离级别
propogation : 事务的传播行为
timeout : 超时时间
read-only : 是否只读
-->
基于注解的声明式事务控制
注解+xml
//业务代码
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, timeout = -1, readOnly = false)
public void testFunction(..) {
方法体
}
<!--配置文件-->
<!--注入spring提供的事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务的注解支持-->
<tx:annotation-driven/>
纯注解(修改核心配置文件)
@Configuration // 声明为spring配置类
@ComponentScan("com.hezhe") // 扫描包
@Import(DataSourceConfig.class) // 导入其他配置类
@EnableTransactionManagement // 事务的注解驱动
public class SpringConifg {
@Bean("transactionManager")
public PlaformTransactionManager getPlatformTransactionManager(@Autowired DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
Spring集成WEB环境
前景概要
-
应用上下文对象(AplicationContext)是通过new ClassClasspathXmlApplicationContext(spring配置文件) 方式获取的,导致每次使用应用上下文对象都需要去加载配置文件,并且会创建多次。
-
web项目可以使用ServletContextListener来监听Web项目的启动,就可以再web启动时就去加载Spring配置文件,创建应用上下文对象,将其存入web项目最大的域servletContxt域中,就可以从任意位置获取应用上下文对象。
-
Spring提供了获取应用上下文的工具
Spring提供了监听器ContextLoaderListener,来加载Spring配置文件,创建应用上下文对象,并存入servletContxt域中,提供了WebApplicationContextUtils供使用者获取应用上下文对象。
具体实现
- 导入依赖
<!--spring集成web坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
- 配置ContextLoaderListener监听器
<!--全局参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--Spring的监听器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
- 工具类获取
ApplicationContext applicationContext=WebApplicationContextUtils.getWebApplicationContext(servletContext);
Object obj = applicationContext.getBean("id");