1.AOP注解配置
package com.feng.zhujie;
//接口
public interface ICustomerService {
//保存
public void save();
//查询
public Integer find();
}
package com.feng.zhujie;
import org.springframework.stereotype.Service;
//实现类
@Service("customerService")
public class CustomerServiceImpl implements ICustomerService{
@Override
public void save() {
// TODO Auto-generated method stub
System.out.println("客户保存");
}
@Override
public Integer find() {
System.out.println("客户查找");
return 88;
// TODO Auto-generated method stub
}
}
//没有接口的类
package com.feng.zhujie;
import org.springframework.stereotype.Service;
@Service("productService")
public class ProductService {
public void save() {
System.out.println("商品保存");
}
public Integer find() {
System.out.println("商品查找");
//测试抛出通知的时候设置异常
//int i=1/0;
return 99;
}
}
//测试类
package com.feng.zhujie;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//Springjunit集成测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpringTest {
//注入要测试bean
@Autowired
private ICustomerService customerService;
@Autowired
private ProductService productService;
//测试
@Test
public void test() {
//基于接口
customerService.save();
customerService.find();
//基于类
productService.save();
productService.find();
}
}
//切面类
package com.feng.zhujie;
import org.aspectj.lang.JoinPoint;
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;
//advice通知增强类
//<bean id="myAspect" class="com.feng.zhujie.MyAspect"></bean>
@Component("MyAspect")
//<aop:aspect ref="myAspect">
@Aspect
public class MyAspect {
//注解前置通知两种方法
// 第一种:可以直接将切入点的表达式或切入点名字写到@Before
@Before("bean(*Service)")
public void before1(JoinPoint joinPoint) {
System.out.println("--111前置通知--");
}
//第二种:可以使用自定义方法,使用@Pointcut定义切入点
/**
* 切入点方法的语法要求:切点方法:private void 无参数、无方法体,方法名为切入点的名称
* 一个通知方法@Before可以使用多个切入点表达式,中间使用“||”符号分隔,用来表示多个切入点
*/
// <aop:point expression="bean(customerService)" id="myPointcut1"/>
@Pointcut(value = "bean(customerService)")
private void myPointcut1() {
}
// <aop:point expression="bean(customerService)" id="myPointcut2"/>
@Pointcut(value = "bean(productService)")
private void myPointcut2() {
}
// <aop:before method="before" pointcut-ref="myPointcut1"/>
// <aop:before method="before" pointcut-ref="myPointcut2"/>
@Before("myPointcut1()||myPointcut2()")
public void before2(JoinPoint joinPoint) {
System.out.println("--222前置通知--");
}
// 后置通知
// target:拦截某一个类型的bean(唯一),表示只对CusotomerServiceImpl类中的方法做后置通知的查找
@AfterReturning(value = "target(com.feng.zhujie.CustomerServiceImpl)", returning = "returnVal")
public void afterReturning(JoinPoint joinPoint, Object returnVal) {
System.out.println("--后置通知--");
}
// 环绕通知
/**
* @Around("execution(* com.feng*.*(..))")
* 增强返回类型任意,所有的com.feng包中的类,类中所有的方法,参数任意 @Around("execution(*
* com.feng..*.*(..))")
* 增强返回类型任意,所有的com.feng包中的类,及其子包中的所有类,类中所有的方法,参数任意 @Around("execution(*
* com.feng..*.save(..))") 增强返回类型任意,所有的com.feng包中的类,及其子包中的所有类,类中以save结尾的方法,参数任意
*/
// 增强com.feng包中的ICustomerService类的子类型的所有方法,参数任意
@Around("execution(* com.feng.zhujie.ICustomerService+.*(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("--环绕通知-前--");
Object object = proceedingJoinPoint.proceed();
System.out.println("--环绕通知-后--");
return object;
}
// 抛出通知
// 切入点表达式:增强所有com包以及子包下面的所有类型的bean的所有方法
@AfterThrowing(value = "within(com..*)", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
System.out.println("--抛出通知--" + "抛出的异常信息" + ex.getMessage());
}
// 最终通知
// 拦截所有以ice结尾的bean
@After("bean(*ice)")
public void after(JoinPoint joinPoint) {
System.out.println("--最终通知--");
}
}
//applicationContext.xml
<!-- 扫描com.feng.zhujie包下的所有Java类 -->
<context:component-scan
base-package="com.feng.zhujie"></context:component-scan>
<!-- 配置aop的aspectj的自动代理 自动扫描bean组件,含有@Aspect的bean,将其为aop管理,开启动态代理 -->
<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>
前置、后置、环绕、最终通知测试
异常通知测试
【扩展补充】:aop代理是使用的spring的内部代理机制,默认是如果有接口就优先对接口代理(jdk动态代理)
问题:如果目标对象有接口,能否只对实现类代理,而不对接口进行代理呢?可以的。
1.在CustomerServiceImpl的子类中添加一个新的方法update(),而接口不要定义update()的方法
package com.feng.zhujie;
import org.springframework.stereotype.Service;
//实现类
@Service("customerService")
public class CustomerServiceImpl implements ICustomerService{
@Override
public void save() {
// TODO Auto-generated method stub
System.out.println("客户保存");
}
@Override
public Integer find() {
System.out.println("客户查找");
return 88;
// TODO Auto-generated method stub
}
//方法在接口没有
public void update() {
System.out.println("客户更新");
}
}
2.在测试类中调用子类的扩展方法
public void test() {
//基于接口
customerService.save();
customerService.find();
//基于类
productService.save();
productService.find();
//执行customerService的update方法
//扩展方法执行:customerServic是一个动态代理对象,原因,该对象是接口的子类型的对象
((CustomerServiceImpl) customerService).update();
}
直接测试发现异常
原因:代理的目标对象是接口,无法转换为子类
解决办法:可以使用类代理(cglib动态代理),只需要设置proxy-target-class=true;
在applicationContex.xml中修改如下配置
<!-- 配置aop的aspectj的自动代理 自动扫描bean组件,含有@Aspect的bean,将其为aop管理,开启动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>