spring知识点
一,IOC和DI
ApplicationContext 获取具体bean对象的接口
ClassPathApplicationContext 该接口的实现类
bean 标签内配置属性
scope 视野,范围,代表bean的作用范围
singleton 单例(默认值)
prototype 多例
request 将创建的对象保存到request域中
session 将创建的对象保存到session域中
globalsession 应用在porlet环境下,将创建的对象保存到全域的session中
init-method 初始化方法
destroy-method 销毁方法
生成bean的三种方法
1,无参构造
2,静态工厂实例化
factory-method 指定工厂类中静态方法的名字
3,实例工厂实例化
factory-bean 指定工厂bean的id
factory-method 指定工厂bean的实例工厂方法名
DI 依赖注入
IOC Inverse of Control 控制反转,对象的创建权利反转给spring
DI Dependency Injection 依赖注入 在spring框架负责创建bean对象时候,动态的将依赖对象注入到bean组件中
构造方法注入(有参构造):
bean标签内标签名:
constructor-arg 标签(name:属性名,value:值)
set方法注入(需要提供set方法):
bean标签内标签名:
property 标签(name:属性名,value:普通属性的值,ref:对象属性的值)
p命名空间注入
bean组件中 p:name(属性名)="值" p:name-ref(对象属性名)="对象名"
SpEL的写法
Spring Expression Language
bean标签内标签名:
property name:属性名 value=下列语法
注入字符串:"#{'字符串'}"
注入数字:"#{数字}"
注入其他对象:"#{对象id}"
还可以注入其他对象属性或方法的返回值
"#{carInfo.name}" 会调用getName方法获取汽车名
"#{carInfo.calculatePrice()}"会直接调用calculatePrice方法获取汽车的价格
集合注入(重点):
<!--特殊类型的注入-->
<bean id="cb" class="my.package.domain.CollectionBean">
<!--数组-->
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
<!--set集合-->
<property name="set">
<set>
<value>小特</value>
<value>小金</value>
<value>小普</value>
</set>
</property>
<!--map集合-->
<property name="map">
<map>
<entry key="id" value="1"></entry>
<entry key="name" value="zhangsan"></entry>
<entry key="password" value="123456"></entry>
</map>
</property>
<!--properties-->
<property name="properties">
<props>
<prop key="id">2</prop>
<prop key="name">小明</prop>
</props>
</property>
</bean>
文件分离
import 标签 resource="applicationContext2.xml"
开闭原则: 对扩展开放,对修改关闭
二、spring的注解使用
注解所需约束
xmls:context
开启注解扫描
<context:component-scan base-package="my.package"/>
常用注解四大类
直接按照Bean的id注入。它也只能注入其他bean类型。与创建bean对象相关:
@Component @Controller @Service @Repository
与注入值相关:
@Value @Autowired(重点) @Qualifier @Resource
与范围相关
@Scope
与生命周期相关
@PostConstruct @PreDestroy
1,用于创建对象的
下列四个作用相同,是把资源 交给spring来管理
相当于在xml中配置了一个bean
@Component("userService") value指定bean的id默认是当前类的类名,首字母小写
@Component:
@Controller(表现层)
@Service(业务层)
@Repository(持久层)
2,用于给对象中的属性注入值
相当于<property name="" value=""/>
@Value 注入基本数据类型和String类型数据
@Autowired 自动按照类型注入。当使用注解注入属性时,set方法可以省略。它只能注入其他bean类型。当有多个类型匹配时,使用要注入的对象变量名称作为bean的id,在spring容器查找,找到了也可以注入成功。找不到就报错。
@Qualifier 在自动按照类型注入的基础之上,再按照Bean的id注入。它在给字段注入时不能独立使用,必须和@Autowire一起使用;但是给方法参数注入时,可以独立使用。
@Resource 按照bean的id注入,只能注入其他bean类型
3,用于改变作用范围
@Scope
属性:value:取值: singleton prototype request session globalsession
添加在类名上面
4,用于定义生命周期
相当于:<bean id="" class="" init-method="" destroy-method=""/>
@PostConstruct 注解
加在方法上,指定bean对象创建好之后,调用该方法初始化对象 类似于xml的init-method方法
@PreDestory注解
加在方法上,指定bean销毁之前,调用该方法
其他注解
@Configuration加在类名上,表示该类是一个配置类
@ComponentScan(base-package="my.package")指定包扫描
@Bean(name="") 加在方法上,表示使用此方法创建一个对象,并且放入spring容器
name属性:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)
@PropertySource("classpath:jdbc.properties")
加在类上,表示该类引入外部资源文件
@Value("${jdbc.username}")
加在属性上表示引入属性资源的key获取的value
配置分离注解:
@Import(JdbcConfig.class)
导入其他配置类
Spring框架整合JUnit单元测试
1,引入依赖spring-test.jar
2,在测试类上添加注解
//指定使用的单元测试执行类
@RunWith(SpringJUnit4classRunner.class)
//指定spring配置文件所在的路径,可以同时指定多个文件
@ContextConfiguration("classpath:applicationContext.xml")
三、spring的AOP编程
AOP Aspect Oriented Programming 面向切面编程
作用:在不修改源代码的情况下,可以实现功能的增强
应用场景:记录日志、监控方法运行时间、权限控制、缓存优化、事务管理
原理:动态代理(JDK+CGLIB)
编写流程:
编写目标类
编写切面类、通知方法
把切面类、目标类交给spring管理
配置AOP
配置切入点表达式、
配置切面:指定用哪个通知方法进行增强
AOP的注解开发
相关术语:
Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点
Pointcut(切入点): 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
Advice(通知/增强): 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Aspect(切面): 是切入点和通知(引介)的结合
Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下,
Introduction: 可以在运行期为类动态地添加一些方法或Field.
Target(目标对象): 代理的目标对象(要增强的类)
Weaving(织入): 是把增强应用到目标的过程.
把advice 应用到 target的过程
Proxy(代理): 一个类被AOP织入增强后,就产生一个结果代理类
所需依赖:spring-aspects
一、AOP配置方法:
<!--AOP配置-->
<aop:config>
<!--配置切入点:告诉spring框架哪些方法需要被增强-->
<aop:pointcut id="pointcut1" expression="execution(* my.package.dao.impl.CustomerDaoImpl.save(..))"/>
<aop:pointcut id="pointcut2" expression="execution(* my.package.dao.impl.CustomerDaoImpl.delete(..))"/>
<aop:pointcut id="pointcut3" expression="execution(* my.package.dao.impl.CustomerDaoImpl.update(..))"/>
<aop:pointcut id="pointcut4" expression="execution(* my.package.dao.impl.CustomerDaoImpl.list(..))"/>
<!--配置切面:告诉spring框架调用切面类中的哪个方法来增强-->
<aop:aspect ref="myAspectXml">
<!--配置前置通知-->
<aop:before method="before" pointcut-ref="pointcut1"/>
<!--配置后置通知-->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut2" returning="result"/>
<!--配置环绕通知-->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!--异常通知-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
<!--最终通知-->
<aop:after method="after" pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
常见写法:
execution(public * *(..)) 所有的public方法
execution(* set*(..)) 所有set开头的方法
execution(* com.xyz.service.AccountService.*(..)) AccountService类中的所有方法
execution(* com.xyz.service..(..)) com.xyz.service包下所有的方法
execution(* com.xyz.service...(..)) com.xyz.service包及其子包下所有的方法
切面类内部方法的参数列表:
//import org.aspectj.lang.JoinPoint;这个包下
Joinpoint joinpoint 连接点,指的是被增强的那个方法
joinpoint.getTarget().getClass().getName();//获取目标类的名字
joinpoint.getSignature().getName();//获取被增强方法的名字
环绕通知的参数和返回值
//proceedingJoinPoint 正在执行的连接点
public Object around(ProceedingJoinPoint proceedingJoinPoint){
//获取目标方法的参数
Object[] args = proceedingJoinPoint.getArgs();
Object result = null;
try {
//获取目标方法的返回值
result = proceedingJoinPoint.proceed(args);
System.out.println("提交事务");
} catch (Throwable throwable) {
System.out.println("回滚事务");
throwable.printStackTrace();
}
//返回目标方法的返回值
return result;
};
异常通知的方法和参数列表
//ex的值要与配置文件中的名字一致
public void afterThrowing(JoinPoint joinPoint, Throwable ex){
//获取异常的信息
ex.getMessage();
}
最终通知
不管目标方法是否发生异常,最终通知都会执行(类似于finally代码功能)
二、AOP的注解方式
在xml配置中开启注解扫描以及自动代理
<context:component-scan base-package="my.package"/>
<aop:aspectj-autoproxy/>
在切面类的类名上面添加注解
@Componet //交给spring管理
@Aspect //表示该类是一个切面类
在切面类中的各个方法上面添加注解
1,前置通知:
@Before("execution(* my.package.dao.impl.CustomerDaoImpl.save(..))")
2,后置通知 应用场景: ATM取款机取款后,自动下发短信 参数result:被增强那个方法的返回值
/**
* 后置通知方法
* 应用场景:
* ATM取款机取款后,自动下发短息
* returning属性指定目标返回值的名字
* @param joinPoint
* @param result 被增强的那个方法的返回值
*/
@AfterReturning(value = "execution(* my.package.dao.impl.CustomerDaoImpl.delete(..))",returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result){
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = sdf.format(date);
System.out.println("尊敬的用户,您于" + dateStr + "取款" + result + "元");
}
3,环绕通知
@Around("execution(* my.package.dao.impl.CustomerDaoImpl.update(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint){}
4,异常通知:作用处理异常
@AfterThrowing(value = "execution(* my.package.dao.impl.CustomerDaoImpl.list(..))",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Throwable ex){
System.out.println("注意了:在" + joinPoint.getTarget().getClass().getName()
+ joinPoint.getSignature().getName() + "方法中发生了异常:" +ex.getMessage());
}
5,最终通知,
应用场景:释放资源:关闭文件、关闭数据库连接、网络连接、释放内存对象
@After("execution(* my.package.dao.impl.CustomerDaoImpl.list(..))")
public void after(JoinPoint joinPoint){}
四、spring的JdbcTemplate
1,JdbcTemplate基本介绍
1)普通方式:
@Test
public void test1(){
// 创建jdbc模板对象
JdbcTemplate jdbcTemplate = new JdbcTemplate();
// 创建druid数据源,其它数据源也行,例如c3p0
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
dataSource.setUsername("root");
dataSource.setPassword("123");
// 设置数据源
jdbcTemplate.setDataSource(dataSource);
// 插入操作
jdbcTemplate.update("insert into account(name,money) values(?,?)", "张三", 1000.0);
}
2)交给spring管理
在applicationContext.xml中进行配置
0,配置bean引入jdbc.properties文件
0.1,方法一,通过bean引入,使用占位符解析器
类名:PropertySourcesPlaceholderConfigurer
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
0.2,方法二,通过context标签引入,需要引入context约束
<context:property-placeholder location="classpath:jdbc.properties"/>
1,配置JdbcTemplate
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
注入数据源:
<property name="dataSource" ref="dataSource"/>
</bean>
2,配置数据源
<bean id=""dataSource class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
2,JdbcTemplate的CRUD
0, 自定义RowMapperd实现类,可以解决字段名与bean实体类名不一致的情况
public class AccountRowMapper implements RowMapper<Account>{
/*把账户表里的一行数据形成账户对象*/
@Override
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account account = new Account();
account.setId(rs.getLong("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
return account;
}
}
1,AccountDaoImpl中的CRUD方法
需要在类中定义
private JdbcTemplate jdbcTemplate;
获得JdbcTemplate有两种方式:
方法1,直接在dao中声明
步骤一,提供set方法 进行依赖注入
或者是使用注解注入
步骤二,在applicationContext.xml中把bean实例化和属性注入交给spring管理
方法2,让dao继承JdbcDaoSupport类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
}
该类中不用再声明jdbcTemplate属性了,因为在其父类中已经声明了
另外,在xml中就不用再手动配置JdbcTemplate了。
两版Dao有什么区别呢?
答案:
第一种在Dao类中定义JdbcTemplate的方式,适用于所有配置方式(xml和注解都可以)。
第二种让Dao继承JdbcDaoSupport的方式,只能用于基于XML的方式,注解用不了。
3,事务的回顾
3.1什么是事务
事务是逻辑上一组操作,组成这组操作各个逻辑单元,要么一起成功,要么一起失败。
3.2事务特性
原子性:强调事务的不可分割.
一致性:事务的执行的前后数据的完整性保持一致.
隔离性:一个事务执行的过程中,不应该受到其他事务的干扰
持久性:事务一旦结束,数据就持久到数据库
3.2如果不考虑隔离性会引发的安全问题
脏读:一个事务读到了另一个事务的未提交的数据
不可重复读:一个事务读到了另一个事务已经提交的update 的数据导致多次查询结果不一致.
虚读:一个事务读到了另一个事务已经提交的insert 的数据导致多次查询结果不一致.
3.3解决读的问题:设置事务隔离级别
- read uncommitted
- read committed
- repeatable read
- Serializable
未提交读:脏读,不可重复读,虚读都有可能发生
已提交读:避免脏读。但是不可重复读和虚读有可能发生
可重复读:避免脏读和不可重复读.但是虚读有可能发生
串行化的:避免以上所有读问题
3.4spring事务管理的API
获取事务状态信息 TransactionStatus getTransaction(TransactionDefinition definition)
提交事务
void commit(TransactionStatus status)
回滚事务
void rollback(TransationStatus staus)
DataSourceTransactionManager//使用springJDBC或iBatis进行持久化数据时使用
HibernateTransactionManager//使用Hibernate3.0版本进行持久化数据时候使用
org.springframework.jdbc.dataSource.DataSourceTransactionManager 使用jdbc或者ibatis进行持久化数据时使用
3.5 事务的传播行为
PROPAGION_XXX :事务的传播行为
* 保证同一个事务中
PROPAGATION_REQUIRED 支持当前事务,如果不存在就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
* 保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行;如果当前没有事务,则执行REQUIRED类似的操作
3.6代码案例
xml配置
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务的属性
id:指定advice的id,后边要用到
transaction-manager:写的是事务管理器的id
-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- find开头的方法加只读事务 ,*表示通配符,匹配任意方法-->
<tx:method name="find*" read-only="true"/>
<!-- 其余方法是加可读写的事务 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切面 -->
<aop:config>
<!-- 配置切入点表达式:告诉框架哪些方法要控制事务 -->
<aop:pointcut expression="execution(* my.package.service.impl.*.*(..))" id="pt"/>
<!--将定义好的事务属性应用到上述的切入点 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>

浙公网安备 33010602011771号