本帖最后由 李志旭 于 2019-7-7 11:19 编辑
三、AOP
1、什么是 AOP,作用及其优势
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
2、 AOP 的底层实现
JDK 代理 : 基于接口的动态代理技术
cglib 代理:基于父类的动态代理技术
3、AOP 相关概念
- Target(目标对象):代理的目标对象
- Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
- Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
- Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
- Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
- Aspect(切面):是切入点和通知(引介)的结合
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
Target target = new Target(); //创建目标对象Enhancer enhancer = new Enhancer(); //创建增强器enhancer.setSuperclass(Target.class); //设置父类enhancer.setCallback(new MethodInterceptor() { //设置回调 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("前置代码增强...."); Object invoke = method.invoke(target, objects); System.out.println("后置代码增强...."); return invoke; }});Target proxy = (Target) enhancer.create(); //创建代理对象
4、基于 XML 的 AOP 开发
①导入 AOP 相关坐标
②创建目标接口和目标类(内部有切点)
③创建切面类(内部有增强方法)
④将目标类和切面类的对象创建权交给 spring
⑤在 applicationContext.xml 中配置织入关系
⑥测试代码
①导入 AOP 相关坐标
<!--导入spring的context坐标,context依赖aop--><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version></dependency><!-- aspectj的织入 --><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version></dependency>
②创建目标接口和目标类(内部有切点)
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("前置代码增强....."); }}
④将目标类和切面类的对象创建权交给 spring
<!--配置目标类--><bean id="target" class="com.itheima.aop.Target"></bean><!--配置切面类--><bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>
⑤在 applicationContext.xml 中配置织入关系
<!--配置切点表达式和前置增强的织入关系--><aop:config> <!--引用myAspect的Bean为切面对象--> <aop:aspect ref="myAspect"> <!--配置Target的method方法执行时要进行myAspect的before方法前置增强--> <aop:before method="before" pointcut="execution(public void com.itheima.aop.Target.method())"></aop:before> </aop:aspect></aop:config>
⑥测试代码
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class AopTest { @Autowired private TargetInterface target; @Test public void test1(){ target.method(); }}
1)表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
execution(public void com.itheima.aop.Target.method()) execution(void com.itheima.aop.Target.*(..))execution(* com.itheima.aop.*.*(..))execution(* com.itheima.aop..*.*(..))execution(* *..*.*(..))
2)通知类型
3)切点表达式的抽取
<aop:config>> <!--引用myAspect的Bean为切面对象--> <aop:aspect ref="myAspect"> <aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))"/> <aop:before method="before" pointcut-ref="myPointcut"></aop:before> </aop:aspect></aop:config>
5、基于注解的 AOP 开发
①创建目标接口和目标类(内部有切点)
②创建切面类(内部有增强方法)
③将目标类和切面类的对象创建权交给 spring
④在切面类中使用注解配置织入关系
⑤在配置文件中开启组件扫描和 AOP 的自动代理
⑥测试
①创建目标接口和目标类(内部有切点target),将目标类交给spring
public interface TargetInterface { public void method();}@Component("target")public class Target implements TargetInterface { @Override public void method() { System.out.println("Target running...."); }}
②创建切面类(内部有增强方法),将切面类的对象创建权交给 spring,在切面类中使用注解配置织入关系
@Component("myAspect")@Aspectpublic class MyAspect { @After("execution(* com.itheima.aop.*.*(..))") public void before(){ System.out.println("前置代码增强....."); } @Before("myPoint()") public void before(){ System.out.println("前置代码增强....."); } //抽取表达式 @Pointcut("execution(* com.itheima.aop.*.*(..))") public void myPoint(){}}
③在配置文件中开启组件扫描和 AOP 的自动代理
<!--组件扫描--><context:component-scan base-package="com.itheima.aop"/><!--aop的自动代理--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
④测试代码
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class AopTest { @Autowired private TargetInterface target; @Test public void test1(){ target.method(); }}
四、JdbcTemplate基本使用
1、JdbcTemplate开发步骤
①导入spring-jdbc和spring-tx坐标
②创建数据库表和实体
③创建JdbcTemplate对象
④执行数据库操作
1)导入spring-jdbc和spring-tx坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.5.RELEASE</version></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.5.RELEASE</version></dependency>
2)创建JdbcTemplate对象
JdbcTemplate jdbcTemplate=new JdbcTemplate();
3)创建dataSource对象,并加入到JdbcTemplate中
ComboPooledDataSource dataSource=new ComboPooledDataSource();dataSource.setDriverClass("com.mysql.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");dataSource.setUser("root");dataSource.setPassword("admin123");jdbcTemplate.setDataSource(dataSource);
4)对数据库进行操作
int i=jdbcTemplate.update("insert into account values(?,?,?)", null,"zhangsan1", 5000);System.out.println(i);
2、JdbcTemplate注入spring容器
<!--加载jdbc.properties--><context:property-placeholder location="classpath:jdbc.properties"/><!--数据源对象--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/></bean><!--jdbc模板对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/></bean>
3、增删改查操作
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class JdbcTemplateCRUDTest { @Autowired private JdbcTemplate jdbcTemplate; //计算总数 @Test public void testQueryCount(){ Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class); System.out.println(count); } //查询单个 @Test public void testQueryOne(){ Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), "tom"); System.out.println(account); } //查询所有 @Test public void testQueryAll(){ List<Account> accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class)); System.out.println(accountList); } //更新 @Test public void testUpdate(){ jdbcTemplate.update("update account set money=? where name=?",10000,"tom"); } //删除 @Test public void testDelete(){ jdbcTemplate.update("delete from account where name=?","tom"); }}
五、Spring的事务控制
1、事务隔离级别
- ISOLATION_DEFAULT(扩展:使用数据库默认,Mysql** 默认:可重复读 ,Oracle 默认:读已提交)
- ISOLATION_READ_UNCOMMITTED(读未提交)
- ISOLATION_READ_COMMITTED(读已提交)
- ISOLATION_REPEATABLE_READ(可重复读)
- ISOLATION_SERIALIZABLE(串行化)
Serializable(串行化):一个事务在执行过程中完全看不到其他事物对数据库所做的更新(事务执行的时候不允许别的事务并发执行,事务只能一个接着一个地执行,而不能并发执行)
Repeatable Read(可重复读):一个事务在执行过程中可以看到其它事务已经提交的新插入的记录,但是不能看到其它事务对已有记录的更新
Read Commited(读已提交数据):一个事务在执行过程中可以看到其它事务已经提交的新插入的记录,而且能看到其它事务已经提交的对已有记录的更新。
Read Uncommitted(读未提交数据):一个事务在执行过程中可以看到其它事务没有提交的新插入的记录的更新,而且能看其它事务没有提交到对已有记录的更新
2、事务传播行为
通俗说法:传播行为就是事务之间相互协商的规则,以谁的规则为准的协商机制
- REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
- MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
- REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
- NEVER:以非事务方式运行,如果当前存在事务,抛出异常
- NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
- 超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置
- 是否只读:建议查询时设置为只读
3、编程式事务控制-TransacionStatus
编程式事务控制三大对象
- PlatformTransactionManager
- TransactionDefinition
- TransactionStatus
4、声明式事务
什么是声明式事务控制
Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。
声明式事务处理的作用
- 事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可
- 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便
声明式事务的四个特征
① Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成 功,要么全部失败。
② Consistency(一致性):事务完成时,数据必须处于一致状态,数据的完整性约束没有被破坏,事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没 有执行过一样。
③ Isolation(隔离性):事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性 和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。
④Durability(持久性):事务结束后,事务处理的结果必须能够得到固化。
5、xml事务配置
<!--配置平台事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/></bean><!--通知 事务的增强--><tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--设置事务的属性信息的--> <tx:attributes> <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/> <tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/> <tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/> <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/> <tx:method name="*"/> </tx:attributes></tx:advice><!--配置事务的aop织入--><aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.itheima.service.impl.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/></aop:config>
6、注解事务配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/></bean><!--事物的注解驱动--><tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout = -1)
|
|