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); }