IOC :控制反转
DI : 依赖注入
set
aspectj 框架是 aop 编程思想的体现, spring-aop 对 aspectj 又进一步的封装 jdk的动态代理 和 Cglib代理 IOC容器组件 实现接口使用 JDK动态代理 ,如果没有实现接口使用 Cglib代理 aspectjweaver aspectjrt spring-aop
aspectj 的封装,因此我们使用起来更加简单 pom.xml 中添加如下依赖 <!-- 导入aspectj依赖 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <!-- 导入spring的aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.2.8.RELEASE</version> </dependency>
@Component //spring自动创建对象
@Aspect //表示当前类是一个切面类
public class DemoAop{
/**
* @Before("bean(bean的名称)") 表示该方法在这个bean中的所有方法执行之前执行
* 其中可以使用通配符,比如bean("*ServiceImpl") 表示全部的service类,比如userServiceImpl
*/
@Before("bean(userServiceImpl)")//方法执行之前
public void before(){
System.out.println("方法执行之前...............");
}
/**
* 在方法之后执行
*/
@After("bean(*ServiceImpl)")
public void after(){
System.out.println("在方法执行之后执行");
}
/**
* 在业务方法没有异常的时候才会执行,并且实在@After之后执行
* 如果业务方法有异常,那么不会执行
*/
@AfterReturning("bean(*ServiceImpl)")
public void afterReturning(){
System.out.println("方法在after之后执行,并且这个业务方法没有出现异常");
}
/**
* 在业务方法发生异常才会执行,并且在@After之后执行
* 如果没有发生异常,不会执行
*/
@AfterThrowing("bean(*ServiceImpl)")
public void afterThrowing(){
System.out.println("方法发生异常执行....");
}
/**
* 环绕通知
* @param jp
* @throws Throwable
*/
@Around("bean(*ServiceImpl)")
public Object test(ProceedingJoinPoint jp)throws Throwable{
System.out.println("环绕通知 .....之前");
//调用业务层的方法,其中的Object是接收业务层方法的返回值
Object object =jp.proceed();
System.out.println("环绕通知..........之后");
return object; //这里的返回值必须返回,否则在业务层将不会获取到
}
}
spring-aop.xm l) <!-- 定义spring组件扫描componet --> <context:component-scanbase-package="cn.tedu.store.aop"/> <!-- 解析切面注解 --> <aop:aspectj-autoproxy/>
@Before :在业务方法执行之前调用 @After :在方法之后执行 @AfterReturning :在方法之后执行,只有在业务方法没有出现异常的时候才会执行 @AfterThrowing : 在方法之后执行,只有在业务方法出现异常的时候才会执行 @Around : 环绕通知,在业务方法执行之前和之后执行,即使在 @Before 之前执行,在 @After之后 执行,必须又返回值,这里的返回值就是业务层方法的返回值,如果不返回,那么业务层方法就获取不到返回值 bena 的切点定义 : (bean("userServiceImpl")) ,这个是作用到该业务类中的所有方法上,并不能定义到某一个方法上 bean("*ServiceImpl") :作用到多个业务层,比如: userServiceImpl , addressServiceImpl bean("userServiceImpl")||bean("addressServiceImpl") : 只作用到当前的两个业务层 (within("全类名")) : 其中写的是全类名 (within("cn.tedu.store.service.UserServiceImpl")) :作用于 UserServiceImpl 这个业务层中的所有方法 (within("cn.tedu.store.service.*ServiceImpl")) : 使用 * 通配符,作用到全部的业务层 ("execution(* cn.tedu.store.service.UserServiceImpl.login(..))") :第一个 * 表示方法的返回类型,一般使用 * 表示,其中的形式是 全类名.方法名(..) ("execution(* cn.tedu.store.service.UserServiceImpl.get*(..))") :这个将作用于 UserServiceImpl 这个业务类中的所有以 get 开头的方法 ("execution(* cn.tedu.store.service.*ServiceImpl.login(..))") : 这个将作用于所有的业务类中的所有以 get 开头的方法 ("execution(* cn.tedu.store..get*(..))") :这个将作用于 cn.tedu.store 这个包和其子包下的所有类中的所有以 get 开头的方法 @Component
@Aspect
public class TestAop{
/**
在调用UserServiceImpl中的login()方法之前执行这个方法
*/
@Before("execution(* cn.tedu.store.service.UserServiceImpl.login(..))")
public void test(){
System.out.println("TestAop.text");
}
/**
* 测试登录的业务方法的性能
*/
@Around("execution(* cn.tedu.store.service.UserServiceImpl.login(..))")
public Object test1(ProceedingJoinPoint jp)throws Throwable{
Long before=System.currentTimeMillis(); //获取执行之前的系统时间
Object object=jp.proceed(); //调用业务层的方法
Long after=System.currentTimeMillis(); //获取执行之后的系统时间
System.out.println(after-before);
return object;
}
}
jdk的动态代理 和 Cglib代理 cglib代理 使用的是 继承 , 动态代理 使用的是 接口 ,如果需要添加横切逻辑的类没有接口,那么使用的是cglib代理,如果有接口,使用的是jdk的动态代理 spring-aop 是对 aspectj 的进一步封装
RuntimeException 或者其子类类型异常时, spring-aop 会捕获异常,并且处理事务 <!-- 配置事务管理器 --> <beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入数据源,这里使用的是上面配置好的DataSource --> <propertyname="dataSource"ref="dataSource"></property> </bean> <!-- 开启事务注解 ,transaction-manager指定的是上面配置的事务管理器的id--> <tx:annotation-driventransaction-manager="transactionManager"/>
@Transactional Service 的接口上添加注解,那么所有的接口方法都会被事务管理器管理 Service 的接口类上添加注解,并且在只涉及到 查询 语句的方法中设置传播行为为只读 @Transactional(readOnly=true) | 名称 | 值 | 解释 |
|---|---|---|
| PROPAGATION_REQUIRED | 0 | 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring默认的事务的传播。 |
| PROPAGATION_SUPPORTS | 1 | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
| PROPAGATION_MANDATORY | 2 | 支持当前事务,如果当前没有事务,就抛出异常。 |
| PROPAGATION_REQUIRES_NEW | 3 | 新建事务,如果当前存在事务,把当前事务挂起。 |
| PROPAGATION_NOT_SUPPORTED | 4 | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
| PROPAGATION_NEVER | 5 | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
| PROPAGATION_NESTED | 6 | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 |
| 名称 | 值 | 解释 |
|---|---|---|
| ISOLATION_DEFAULT | -1 | 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应 |
| ISOLATION_READ_UNCOMMITTED | 1 | 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。 |
| ISOLATION_READ_COMMITTED | 2 | 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 |
| ISOLATION_REPEATABLE_READ | 4 | 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。 |
| ISOLATION_SERIALIZABLE | 8 | 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。 |
Service 接口上添加了 @Transactional 这个注解,那么默认这个接口中所有的方法都会被事务管理,因为这些方法都使用了默认的传播属性 PROPAGATION_REQUIRED ,我们可以在只涉及到 查询 语句的方法上添加 @Transactional(readyOnly=true) ,这样可以优化事务管理 /**
* 博客的业务层接口
* @author chenjiabing
*/
@Transactional //在接口中添加事务管理,那么其中的所有方法都被事务管理了
public interface IBlogService{
/**
* 获取当前用户的所有博客分类
* @param bloggerId 博主id
* @return
*/
@Transactional(readOnly=true) //设置传播属性为只读,因为其中只涉及了查询语句
List<BlogType>getBlogTypeList(Integer bloggerId);
/**
* 添加博客
* @param blog Blog对象,其中封装了需要添加的内容
*/
// @Transactional(propagation=Propagation.REQUIRED) //这个是默认的,可以不用定义,因为在接口上已经定义了
void addBlog(Blog blog);
/**
* 分页获取博客总数
* @param bloggerId
* @param offest
* @param count
* @return
*/
@Transactional(readOnly=true)
List<Blog>getBlogList(Integer bloggerId,Integer offest,Integer count);
/**
* 获取博客总数
* @param bloggerId
* @return
*/
@Transactional(readOnly=true)
IntegergetBlogCount(Integer bloggerId,String title,Integer typeId);
/**
* 批量删除博客
* @param ids
*/
void moveBlogByIdsBatch(Integer[] ids);
/**
* 根据id查询博客信息
* @param id 主键id
* @return 返回Blog对象,其中封装了需要的信息
*/
@Transactional(readOnly=true)
BloggetBlogById(Integer id);
/**
* 根据日期分类
* @param bloggerId
* @return
*/
@Transactional(readOnly=true)
List<Blog_Count_ReleaseDateStr_Vo>getBlogGroupByReleaseDateStr(Integer bloggerId);
/**
* 按照博客分类来获取博客信息
* @param typeId 分类id
* @return
*/
@Transactional(readOnly=true)
List<Blog>getBlogByTypeId(Integer typeId,Integer offest,Integer count);
/**
* 按照日期分类获取博客信息
* @param bloggerId 博主id
* @param releaseDateStr 日期
* @param offest 偏移量
* @param count 数量
* @return
*/
@Transactional(readOnly=true)
List<Blog>getBlogByreleaseDateStr(@Param("bloggerId")Integer bloggerId,@Param("releaseDateStr")String releaseDateStr,@Param("offest")Integer offest,@Param("count")Integer count);
/**
* 按照日期查询博客数量
* @param bloggerId 博主id
* @param releaseDateStr 日期
* @return
*/
@Transactional(readOnly=true)
IntegergetBlogCount(Integer bloggerId,String releaseDateStr);
/**
* 修改博客的点击次数
* @param id
* @param clickHit
*/
void modifyclickHit(Integer id,Integer clickHit);
}