Spring
IOC控制反转,依赖注入,基于OOP设计的对象管理容器,实现代码的解耦。
解耦:降低程序之间的依赖关系,应该做到编译期不依赖,运行时才依赖。
AOP面向切面编程,在程序运行期间,不修改源码对已有方法进行增强。
1.基于xml
IOC
1.创建bean的方式
默认构造函数创建
<bean id = "accountService" class="com.ithiema.impl.AccountServiceImp"></bean>
普通工厂创建
<bean id="instanceFactory" class="com.itheima.factory.instanceFactory"></bean>
<bean id="accountSerice" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
工厂的静态方法注入
<bean id=accountService" class="com.itheima.StaticFactory" factory-method="getAccountService"></bean>
2.作用范围
bean标签的scope属性
singleton:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围 每次请求都会创建一个对象
session:作用于web应用的会话范围 每次会话都会创建一个对象
global-session:全局会话范围,当不是集群环境是他就是session
3.生命周期
单例:
出生:当容器创建时出生
活着:容器还在就一直活着
死亡:容器销毁就消亡
总结:单例对象的生命周期和容器相同
多例对象:
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着
死亡:当对象长期不用,且没有别的对象引用时,由JAVA的垃圾回收器回收
4.依赖注入
函数注入
constructor-arg
属性:
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的Bean
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
set方法注入
注入的属性需要提供Set方法
property
属性:
name:找的是类中 set 方法后面的部分
ref:给属性赋值是其他 bean 类型的
value:给属性赋值是基本数据类型和 string 类型的
集合注入
<!--
注入集合数据List 结构的:array,list,set
Map 结构的map,entry,props,prop
-->
<property name="myStrs">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myMap">
<props>
<prop key="testA">aaa</prop>
<prop key="testB">bbb</prop>
</props>
</property>
AOP
1.概念
Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的
连接点。
Pointcut(切入点):
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
Advice(通知/增强):
所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):
引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方
法或 Field。
Target(目标对象):
代理的目标对象。
Weaving(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Proxy(代理):
一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect(切面):
是切入点和通知(引介)的结合
2.配置AOP
<?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">
<!-- 配置 service -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置 dao -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dbAssit" ref="dbAssit"></property>
</bean>
<!-- 配置数据库操作对象 -->
<bean id="dbAssit" class="com.itheima.dbassit.DBAssit">
<property name="dataSource" ref="dataSource"></property>
<!-- 指定 connection 和线程绑定 -->
<property name="useCurrentConnection" value="true"></property>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///spring_day02"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>
<!-- 配置公共方法做成通知 -->
<bean id="txManager" class="com.itheima.utils.TransactionManager">
<property name="dbAssit" ref="dbAssit"></property>
</bean>
<!-- AOP配置 -->
<aop:config>
<!-- 切入点表达式 -->
<aop:pointcut expression="execution(
public void com.itheima.service.impl.AccountServiceImpl.transfer(
java.lang.String, java.lang.String, java.lang.Float) )" id="pt1"/>
<aop:aspect id="txAdvice" ref="txManager">
<aop:before method="beginTransaction" pointcut-ref="pt1"/>
<aop:after-returning method="commit" pointcut-ref="pt1"/>
<aop:after-throwing method="rollback" pointcut-ref="pt1"/>
<aop:after method="release" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
</beans>
切入点表达式说明
execution:匹配方法的执行(常用)
execution(表达式)
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
注:
通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。
execution(* com.itheima.service.impl.*.*(..))
环绕通知
其他通知是在切点方法的前后添加增强方法,环绕通知是获取切点方法,在通知中添加增强语句。
需要使用ProceedingJoinPoint pjp 去获取参数执行方法
配置方式:
<aop:config>
<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pt1"/>
<aop:aspect id="txAdvice" ref="txManager">
<!-- 配置环绕通知 -->
<aop:around method="transactionAround" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
aop:around:
作用:
用于配置环绕通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
说明:
它是 spring 框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式。
注意:
通常情况下,环绕通知都是独立使用的
@Around
作用:
把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
/**
* 环绕通知
* @param pjp
* @return
*/
@Around("execution(* com.itheima.service.impl.*.*(..))")
public Object transactionAround(ProceedingJoinPoint pjp) {
//定义返回值
Object rtValue = null;
try {
//获取方法执行所需的参数
Object[] args = pjp.getArgs();
//前置通知:开启事务
beginTransaction();
//执行方法
rtValue = pjp.proceed(args);
//后置通知:提交事务
commit();
}catch(Throwable e) {
//异常通知:回滚事务
rollback();
e.printStackTrace();
}finally {
//最终通知:释放资源
release();
}
return rtValue; }
3.事务控制
一、导入依赖
二、spring配置文件中加入依赖
三、准备库和表
四、编写实现类和业务层
五、编写dao接口和实现类
配置步骤
事务控制依赖AOP
<!-- 配置一个事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入 DataSource -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务的配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 指定方法名称:是业务核心方法
read-only:是否是只读事务。默认 false,不只读。
isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
propagation:指定事务的传播行为。
timeout:指定超时时间。默认值为:-1。永不超时。
rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。
没有默认值,任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回
滚。没有默认值,任何异常都回滚。
-->
<tx:method name="*" read-only="false" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 配置 aop -->
<aop:config>
<!-- 配置切入点表达式 -->
<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))"id="pt1"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
</aop:config>
使用
public static void mian(String[] args){
//获取核心容器对象
ApplicationContext ac = new ClassPathXmlApplicatonContext("bean.xml");
//根据id获取bean对象
IAccountService as = (IAccountService)ac.getBean("accountService");
System.out.println(as);
}
//第二种方式使用
Resource resource = new ClassPathResource("bean.xml");
BeanFactory factory = new XmlBeanFactory(resource);
IAccountService accountService = (IAccountService)
actory.getBean("accountService");
/*
Application的三个常用实现类
ClassPathXmlApplicationContext:可以加载类路劲下的配置文件,要求配置文件必须在类路劲下。
FileSystemXmlApplicationContext:可以加载磁盘任意路劲下的配置文件(需要有访问权限)
AnnotationConfigApplicationContext:读取注解创建的容器
核心容器两个接口的问题:
ApplicationContext:创建对象采用的策略是即可加载,读取完配置文件就创建对象
BeanFactory:创建对象采用策略是延迟加载,什么时候根据id获取对象,什么时候创建对象
*/
2.基于注解
IOC
步骤
一、导入aop依赖
二、使用注解配置管理的资源
三、创建Spring配置文件添加开启注解的支持
<!-- 告知 spring 创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
1.创建对象
@Component, @Controller @Service @Repository
value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。
2.作用范围
@Scope
value:指定范围的值。
取值:singleton prototype request session globalsession
3.生命周期
@PostConstruct
作用:用于指定初始化方法。
@PreDestroy
作用:用于指定销毁方法
4.注入数据
@Autowired
作用:
自动按照类型注入。当使用注解注入属性时,set 方法可以省略。它只能注入其他 bean 类型。当有多个
类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到
就报错。
@Qualifier
作用:
在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和
@Autowire 一起使用;但是给方法参数注入时,可以独立使用。
属性:
value:指定 bean 的 id。
@Resource
作用:
直接按照 Bean 的 id 注入。它也只能注入其他 bean 类型。
属性:
name:指定 bean 的 id
@Value
作用:
注入基本数据类型和 String 类型数据的
属性:
value:用于指定值
5.新注解
@Configuration
作用:
用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用
AnnotationApplicationContext(有@Configuration 注解的类.class)。
属性:
value:用于指定配置类的字节码
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class)
@ComponentScan
作用:
用于指定 spring 在初始化容器时要扫描的包。作用和在 spring 的 xml 配置文件中的:
<context:component-scan base-package="com.itheima"/>是一样的。
属性:
basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。
@Bean
作用:
该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。
属性:
name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)
将返回值创建对象存储到容器
@PropertySource
用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到
properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
属性:
value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig()
@Import
作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问题。
属性:value[]:用于指定其他配置类的字节
6.整合JUNIT
1.导入依赖
2.使用@Runwith注解替换原来的运行
3.使用@ContextConfiguration 指定 spring 配置文件的位置
@ContextConfiguration 注解:
locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明
classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。
使用
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
@Autowired
private IAccountService as ; }
AOP
步骤
一、通知类使用注解配置@Componnet
二、在通知类上使用@Aspect生命为切面
三、增强的方法上配置注解**@Before**,@AfterReturning,@AfterThrowing,@After,@Around
四、在spring配置文件中开启注解AOP的支持
<aop:aspectj-autoproxy/>
切入点表达式注解
@Pointcut
作用:
指定切入点表达式
属性:value:指定表达式的内容
@Pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1() {}
@Around("pt1()")//注意:千万别忘了写括号
public Object transactionAround(ProceedingJoinPoint pjp) {
//定义返回值
Object rtValue = null;
try {
//获取方法执行所需的参数
Object[] args = pjp.getArgs();
//前置通知:开启事务
beginTransaction();
//执行方法
rtValue = pjp.proceed(args);
//后置通知:提交事务
commit();
}catch(Throwable e) {
//异常通知:回滚事务
rollback();
e.printStackTrace();
}finally {
//最终通知:释放资源
release();
}
return rtValue; }
不使用XML配置
@Configuration
@ComponentScan(basePackages="com.itheima")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}
事务控制
1.配置事务注入数据源
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property>
</bean>
2.在业务层上使用注解
@Service("accountService")
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
public class AccountServiceImpl implements IAccountService {
}
该注解的属性和 xml 中的属性含义一致。该注解可以出现在接口上,类上和方法上。
出现接口上,表示该接口的所有实现类都有事务支持。
出现在类上,表示类中所有方法有事务支持
出现在方法上,表示方法有事务支持。
以上三个位置的优先级:方法>类>接口
3.开启注解对事务的支持
<!-- 开启 spring 对注解事务的支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/
不使用xml配置
@Configuration
@EnableTransactionManagement
public class SpringTxConfiguration {
//里面配置数据源,配置 JdbcTemplate,配置事务管理器。在之前的步骤已经写过了。
}