切入点表达式说明
匹配方法的执行(常用)
execution(表达式)
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
写法说明:
- 全匹配方式:
public void org.cjw.service.impl.CustomerServiceImpl.saveCustomer()
- 访问修饰符可以省略
void org.cjw.service.impl.CustomerServiceImpl.saveCustomer()
- 返回值可以使用号,表示任意返回值
` org.cjw.service.impl.CustomerServiceImpl.saveCustomer()` - 包名可以使用号,表示任意包,但是有几级包,需要写几个:
* *.*.*.*.CustomerServiceImpl.saveCustomer()
- 使用
..
来表示当前包,及其子包* org..CustomerServiceImpl.saveCustomer()
- 类名可以使用号,表示任意类
` org..*.saveCustomer()` - 方法名可以使用号,表示任意方法
` org...()` - 参数列表可以使用,表示参数可以是任意数据类型,但是必须有参数
` org...(*)` - 参数列表可以使用
..
表示有无参数均可,有参数可以是任意类型* org..*.*(..)
- 全通配方式:
* *..*.*(..)
基于XML配置AOP
首先介绍通过XML的方式配置AOP。
搭建环境
第一步:创建一个Java项目
需求:编写一个切面类,在执行insert,update方法,分别在方法执行前、执行后、异常出现后、调用编写统一处理的代码。
—创建一个Java项目,加入Spring框架的基础支持包。
第二步:编写业务层类和接口
UserService 接口
public interface UserService {
void insert();
void update();
}
业务层UserServiceImpl 实现类
public class UserServiceImpl implements UserService {
@Override
public void insert() {
System.out.println("执行了service层的insert方法");
}
@Override
public void update() {
System.out.println("执行了service层的update方法");
}
}
第三步:编写Spring配置文件
引入aop的命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置UserService -->
<bean id="userService" class="org.cjw.service.impl.UserServiceImpl" />
</beans>
第四步:测试
—测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserServiceTest {
@Resource(name = "userService")
private UserService userService;
@Test
public void testInsert() {
userService.insert();
}
@Test
public void testUpdate() {
userService.update();
}
}
—测试结果
配置AOP
第一步:加入AOP的支持包
AOP 思想必须使用AspectJ语法,而AOP思想不是Spring框架设计出来的,而是叫一个AOP联盟组织提出这种思想,所以开发者需要导入AOP联盟提供的 aspectj.weaver.jar(aspectweaver织入包)。
第二步:编写一个切面类
public class TransactionMangerHandler {
// 前置增强
public void begin() {
System.out.println("开启事务");
}
// 后置增强
public void commit() {
System.out.println("提交事务");
}
// 异常增强
public void rollback() {
System.out.println("回滚事务");
}
// 最终增强
public void closeSession() {
System.out.println("关闭session");
}
}
第三步:配置AOP配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置UserService -->
<bean id="userService" class="org.cjw.service.impl.UserServiceImpl" />
<!-- 配置事务管理器 -->
<bean id="txManger" class="org.cjw.proxyHandler.TransactionMangerHandler" />
<!-- 配置aop -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect ref="txManger">
<!-- 配置切入点:哪些类中的哪些方法需要做增强(where) -->
<aop:pointcut id="pt" expression="execution(* org.cjw.service..*.*(..))" />
<!-- 前置增强 -->
<aop:before method="begin" pointcut-ref="pt" />
<!-- 后置增强 -->
<aop:after-returning method="commit" pointcut-ref="pt" />
<!-- 异常增强 -->
<aop:after-throwing method="rollback" pointcut-ref="pt" />
<!-- 最终增强 -->
<aop:after method="closeSession" pointcut-ref="pt" />
</aop:aspect>
<!-- 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)-->
</aop:config>
</beans>
第四步:测试
测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserServiceTest {
@Resource(name = "userService")
private UserService userService;
@Test
public void testInsert() {
userService.insert();
}
@Test
public void testUpdate() {
userService.update();
}
}
测试结果
思考
问题:编写一个切面需要分别编写前置增强、后置增强、异常增强、最终增强,需要使用到4个标签,有没有办法只用一个标签就完成这4种增强呢?
答:使用环绕增强<aop:aorund>
改写切面类
public class TransactionMangerHandler {
// 环绕增强
public void allInOne(ProceedingJoinPoint pjp) {
try {
begin(); // 前置增强
pjp.proceed(); // 执行被调用的方法
commit(); // 后置增强
} catch (Throwable e) {
e.printStackTrace();
rollback(); // 异常增强
} finally {
closeSession(); // 最终增强
}
}
// 前置增强
public void begin() {
System.out.println("开启事务");
}
// 后置增强
public void commit() {
System.out.println("提交事务");
}
// 异常增强
public void rollback() {
System.out.println("回滚事务");
}
// 最终增强
public void closeSession() {
System.out.println("关闭session");
}
}
—aop配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置UserService -->
<bean id="userService" class="org.cjw.service.impl.UserServiceImpl" />
<!-- 配置事务管理器 -->
<bean id="txManger" class="org.cjw.proxyHandler.TransactionMangerHandler" />
<!-- 配置aop -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect ref="txManger">
<!-- 配置切入点:哪些类中的哪些方法需要做增强(where) -->
<aop:pointcut id="pt" expression="execution(* org.cjw.service..*.*(..))" />
<!-- 环绕增强 -->
<aop:around method="allInOne" pointcut-ref="pt" />
</aop:aspect>
<!-- 织入(Weaving):把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)-->
</aop:config>
</beans>
测试代码
同上
测试结果
常用标签说明
- 2.4.1.
**<aop:config>**
作用:用于声明aop配置
- 2.4.2.
**<aop:aspect>**
作用: 用于配置切面。
属性:
- id:给切面一个唯一标识。
- ref:引用配置好的切面类bean的id。
- 2.4.3.
<aop:pointcut>
作用:用于配置切入点表达式
属性:
- id:用于给切入点表达式一个唯一标识。
- expression:用于定义切入点表达式。
- 2.4.4.
<aop:before>
作用:用于配置前置通知
属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 2.4.5.
<aop:after-returning>
作用:用于配置后置通知,如果出了异常就一定不会调用切面的方法
属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 2.4.6.
<aop:after-throwing>
作用: 用于配置异常通知,只有出了异常才会调用切面对应的方法
属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 2.4.7.
<aop:after>
作用:用于配置最终通知,不管出不出异常,都调用切面的方法
属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 2.4.8.
<aop:around>
作用:用于配置环绕通知
属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
基于注解配置AOP
接下来介绍基于注解的方式配置AOP。
搭建环境
第一步:创建一个Java项目
同上。
第二步:创建UserService接口及其实现类
public interface UserService {
void insert();
void update();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void insert() {
System.out.println("执行了service层的insert方法");
}
}
第三步:编写Spring配置类
@Configuration
@ComponentScan(basePackages = "org.cjw")
public class SpringConfig {
}
第四步:测试
测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {
@Autowired
@Qualifier("userService")
private UserService userService;
@Test
public void testInsert() {
userService.insert();
}
}
测试结果
配置AOP
第一步:加入AOP的支持包
—注意:必须要导入加入支持AOP的包。
Spring的AOP包基于AspectJ框架,所以必须加入AspectJ—>aspectjweaver.jar。
第二步:编写一个切面类
@Component
@Aspect
public class TransactionMangerHandler {
// 环绕增强
@Around("pointcut()")
public void allInOne(ProceedingJoinPoint pjp) {
try {
begin(); // 前置增强
pjp.proceed(); // 执行被调用的方法
commit(); // 后置增强
} catch (Throwable e) {
e.printStackTrace();
rollback(); // 异常增强
} finally {
closeSession(); // 最终增强
}
}
@Pointcut("execution(* org.cjw..*.*(..))") // 等价于<aop:pointcut id="等价于方法名" expression="execution(* org.cjw..*.*(..))">
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("提交事务");
}
// 异常增强
@AfterThrowing("pointcut()") // 等价于<aop:after-throwing method="rollback" pointcut-ref="pt" />
public void rollback() {
System.out.println("回滚事务");
}
// 最终增强
@After("pointcut()") // 等价于<aop:after method="closeSession" pointcut-ref="pt" />
public void closeSession() {
System.out.println("关闭session");
}
}
第三步:配置AOP配置
@Configuration
@ComponentScan(basePackages = "org.cjw")
@EnableAspectJAutoProxy // 开启注解配置AOP
public class SpringConfig {
}
第四步:测试
—测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {
@Autowired
@Qualifier("userService")
private UserService userService;
@Test
public void testInsert() {
userService.insert();
}
}
测试结果
常用注解
- @Aspect
作用:把当前类声明为切面类。
- @Before
作用:把当前方法看成是前置通知。
属性:
value
:用于指定切入点表达式,还可以指定切入点表达式的引用。
- @AfterReturning
作用:把当前方法看成是最终通知。报异常,就不执行。
属性:
value
:用于指定切入点表达式,还可以指定切入点表达式的引用。
- @AfterThrowing
作用:把当前方法看成是异常通知。只有报异常才执行
属性:
value
:用于指定切入点表达式,还可以指定切入点表达式的引用。
例子:
- @After
作用:把当前方法看成是后置通知。不管报不报异常都执行
属性:
value
:用于指定切入点表达式,还可以指定切入点表达式的引用。
- @Around
作用:把当前方法看成是环绕通知。
属性:
value
:用于指定切入点表达式,还可以指定切入点表达式的引用。
- @Pointcut
作用:指定切入点表达式
属性:
综合例子
@Aspect
@Component
public class NotVeryUsefulAspect {
@AfterReturning(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
private void logReceiver(){
System.out.println("切入点logReceiver...");
}
@Pointcut(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..)) && args(param)")
private void pointcut(String param){
System.out.println("切入点pointcut()"+param);
}
//方法体将不执行
@Pointcut("within(com.cn.spring.aspectj.*)")
public String inWebLayer() {
System.out.println("切入点inWebLayer()");
return "返回值加载";
}
@Before(value="inWebLayer()")
private void beforeinWebLayer(){
System.out.println("beforeinWebLayer~~");
}
@Before(value="pointcut(param)")
private void beforePointcut(String param){
System.out.println("beforePointcut:"+param);
}
@AfterReturning(pointcut="inWebLayer()",returning="retVal")
public void doAccessCheck(Object retVal) {
System.out.println("doAccessCheck:"+retVal);
}
@Around(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
private Object aroundLayer(ProceedingJoinPoint pjp) throws Throwable{
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
System.out.println("aroundLayer~~");
return retVal;
}
}
Spring AOP使用小结
Spring AOP xml配置
(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
>环绕通知
Spring AOP 注解配置
(1) 在配置文件/配置类开启注解配置。
① xml:`<aop:aspectj-autoproxy/>`<br /> ② annotation:在java配置类中贴上`@EnableAspectJAutoProxt`注解,作用等同于在xml配置文件中编写`<aop:aspectj-autoproxy>`
(2) @Aspect
在类贴上这个注解,把对应的类当前切面配置类。
(3) @Pointcut
切入点注解
(4)@Before
前置通知注解
(5)@After
后置通知注解
(6)@Aftertrhowing
异常通知注解
(7)@Afterreturing
最终通知注解
(8) @Around
环绕通知注解