基于注解配置AOP
基于注解配置AOP
搭建环境
第一步:创建一个Java项目
创建一个Java项目,加入Spring框架的基础支持包
第二步:编写业务层类和接口
UserService 接口
package cn.xc.spring.service;
import cn.xc.spring.pojo.User;
public interface UserService {
void insert(User user);
void update(User user);
}
业务层UserServiceImpl 实现类
package cn.xc.spring.service.impl;
import cn.xc.spring.pojo.User;
import cn.xc.spring.service.UserService;
@Service
public class UserServiceImpl implements UserService{
public void insert(User user) {
System.out.println("---调用DAO层保存方法---");
}
public void update(User user) {
System.out.println("---调用DAO层修改方法---");
}
}
第三步:编写Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring配置的根元素+约束 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 配置注解扫描包位置 -->
<context:component-scan base-package="cn.xc.spring"/>
</beans>
第四步:编写测试代码
package cn.xc.spring.test;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cn.xc.spring.pojo.User;
import cn.xc.spring.service.impl.UserServiceImpl;
@RunWith(SpringJUnit4ClassRunner.class)
//读取Spring配置文件 xml
//@ContextConfiguration("classpath:applicationContext.xml")
//读取Spring配置文件 java类做配置文件
@ContextConfiguration(classes = {SpringConfig.class})
public class UserServiceTest {
@Resource
private UserServiceImpl service;
@Test
public void testSave() {
User user = new User(null, "张三", "zhangsan@qq.com");
service.insert(user);
}
@Test
public void testUpdate() {
User user = new User(1, "李四", "lisi@qq.com");
service.update(user);
}
}
配置AOP
第一步:加入AOP的支持包
–注意:必须要导入加入支持AOP的包。
Spring的AOP包基于AspectJ框架,所以必须加入AspectJ–>aspectjweaver.jar
第二步:编写一个切面类
package cn.xc.spring;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect //在此类中可以使用注解进行aop的相关配置 <aop:aspect>
public class TransactionManagerHandler {
//<aop:pointcut expression="execution( * cn.zj.spring.service..*.*(..))" id="当前方法名就是id"/>
@Pointcut("execution( * cn.xc.spring.service..*.*(..))")
public void pointcut() {}
@Before("pointcut()") //<aop:before method="begin" pointcut-ref="pt"/>
public void begin() {
System.out.println("开启事务");
}
@AfterReturning("pointcut()")//<aop:after-returning method="commit" pointcut-ref="pt"/>
public void commit() {
System.out.println("提交事务");
}
//<aop:after-throwing throwing="e" method="rollback" pointcut-ref="pt"/>
@AfterThrowing(pointcut="pointcut()",throwing="ex")
public void rollback(Throwable ex) {
System.out.println("注解的回滚事务 : " + ex.getMessage());
}
@After("pointcut()")//<aop:after method="close" pointcut-ref="pt"/>
public void close() {
System.out.println("关闭session");
}
//环绕增强
@Around("pointcut()") //<aop:around method="allInOne" pointcut-ref="pt"/>
public Object allInOne(ProceedingJoinPoint pjp) {
Object result = null;
try {
System.out.println("开启事务------");
//执行被代理对象当前需要执行业务方法
result = pjp.proceed();
System.out.println("提交事务------");
} catch (Throwable ex) {
System.out.println("------回滚事务 : " + ex.getMessage());
}finally {
System.out.println("关闭session------");
}
return result;
}
}
第三步:配置AOP配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 配置spring的包扫描 -->
<context:component-scan base-package="cn.xc.spring"/>
<!-- 使用注解配置AOP配置配置自动注入AOP -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
纯注解配置
package cn.xc.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("cn.xc.spring")
@EnableAspectJAutoProxy //开启aop注解配置
public class SpringConfig {
}
常用注解
@Aspect
作用:
把当前类声明为切面类。
@Before
作用:
把当前方法看成是前置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
@AfterReturning
作用:
把当前方法看成是最终通知。报异常,就不执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
@AfterThrowing
作用:
把当前方法看成是异常通知。只有报异常才执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
@After
作用:
把当前方法看成是后置通知。不管报不报异常都执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
@Around
作用:
把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
@Pointcut
作用:
指定切入点表达式
属性:
value:指定表达式的内容
小结
AOP 面向切面切面编程
为什么要有AOP 编程?
问题:service层在实际开发中要处理事务,日志等操作,这些操作是和业务无关代码,但是又不能少,而且每个方法都有,大量重复,如何把这些代码抽取出去
解决方案:此种场景只能使用Java的动态代理技术解决。为Service层的类创建代理对象。在代理对象中为 各个方法进行增强,使用的时候直接面向代理对象。调用代理对象方法。代理对象底层还是会调用真实对象的方法,但是在 方法执行之前,之后,异常,最终都可以做相应增强
代理模式
Java中有一种设计模式,就是代理模式,讲解就上面问题解决方案,是一种思想
动态代理技术 :实际上就是对代理模式思想的一种具体实现
- JDK动态代理-Java官方
(1) 使用方法
① Object proxy = Proxy.newProxuInstacne(classLoader,interfaces,h)
- classLoader: 类加载
- 被代理对象的接口的字节码实例
- 处理器,开发者具体做增的地方
a. 开发需要自己创建匿名内部内
(2) 缺点:只能代理有接口的类
- CGLIB 第三方代理
(1) 使用方法
① Enhancer
(2) 优点:既可以代理有接口的,又可以代理没有接口的类
① 但是不能代理 final 修饰类或者方法
动态代理能解决主要问题:代码重复问题,但是引来新的小问题(所有方法都代理,不能按照指定规则配置代理方法等等)
SpringAOP ,Spring的AOP在代理的基础之上,增加可以 指定规则 配置对应的代理
SpringAOP 开发者不需要写过多的程序主要编写 Spring配置代码
- SpringAOPxml配置
(1) 在xml配置文件中引入新的 aop 命名空间
(2) Springaop xml配置标签
① <aop:config> 开启aop配置,aop所有配置都在此标签内部配置
- <aop:ponitcut exepression=”切入点语法” id=””> 配置切入点
- <aop:apect ref=“引入要增强的bean(模拟事务管理器)”> 配置切面
a. <aop:before>前置通知
b. <aop:aftereturning>后置通知
c. <aop:afterthrowing>异常通知
d. <aop:after>最终通知
e. <aop:around>环绕通知
- SpringAOP注解配置
(1) 在配置文件汇总开启注解配置
① <aop:aspectj-autoproxy/>
(2) 纯注解,再 Spring的java配置类上面贴上注解
① @EnableAspectJAutoProxy
(3) @Aspect 在类贴上这个注解,把对应的类当前切面配置类
(4) @Pointcut 切入点注解
(5) @Before 前置通知注解
(6) @After 后置通知注解
(7) @Aftertrhowing 异常通知注解
(8) @Afterreturing 最终通知注解
(9) @Around 环绕通知注解