需要的jar包:
com.springsource.net.sf.cglib -2.2.0.jar
com.springsource.org.aopalliance-1.0.0 .jar
com.springsource.org.aspectj.weaver-1.6.8 .RELEASE.jar
commons-logging-1.1.3. jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE. jar
一、创建一个接口
public interface MyMath {
public int add(int i,int j);
public void sub(int i,int j);
public void mul(int i,int j);
public void div(int i,int j);
}
二、创建一个类实现上面的接口
这里使用了@component注解的方式将MymathImpl对象注入到IOC容器中
@Component
public class MyMathImpl implements MyMath{
@Override
public int add(int i, int j) {
int result=i+j;
System.out.println("目标方法add执行了, "+result);
return result;
}
@Override
public void sub(int i, int j) {
// TODO Auto-generated method stub
int result=i-j;
System.out.println("目标方法sub执行了, "+result);
}
@Override
public void mul(int i, int j) {
// TODO Auto-generated method stub
int result=i*j;
System.out.println("目标方法mul执行了, "+result);
}
@Override
public void div(int i, int j) {
// TODO Auto-generated method stub
int result=i/j;
System.out.println("目标方法div执行了, "+result);
}
}
因为使用注解,所以在applicationcontext.xml 中需要扫描包
<?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: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-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <1--扫描包--> <context:component-scan base-package="com.neuedu"></context:component-scan>
</beans>
三、创建一个切面类
1.开启基于注解的AOP功能
< aop:aspectj-autoproxy />
需要在applicationcontext.xml 中配置
<?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" xmlns:context="http://www.springframework.org/schema/context" 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-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!--扫描包 --> <context:component-scan base-package="com.neuedu.bean"></context:component-scan> <!-- 开启AOP注解 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
2.声明一个切面类,并把这个切面类加入到IOC容器中
@Aspect//表示这是一个切面类
@Component//加入IOC容器
@Component @Aspect public class MyMathAspect { @Pointcut(value="execution(public * com.neuedu.bean.MyMathImpl.*(..))") public void showLog(){ }
@Before(value = "showLog()") public void showBeforLog(JoinPoint point ){ Object[] args = point.getArgs(); List<Object> asList = Arrays.asList(args); Signature signature = point.getSignature(); String name = signature.getName(); System.out.println("日志,前置通知,参数为:"+name+"方法为:"+asList); } @After(value = "showLog()") public void showAfterLog(){ System.out.println("日志,后置通知"); } @AfterThrowing(value = "showLog()",throwing="ex") public void showAfterThrowingLog(Exception ex){ System.out.println("日志,异常通知,异常信息为 "+ex); } @AfterReturning(value = "showLog()",returning="result") public void showAfterReturningLog(Object result){ System.out.println("日志,返回置通知,结果为: "+result); } }
3.说明:1) [1]前置通知:@Before
[2]返回通知:@AfterReturning
[3]异常通知:@AfterThrowing
[4]后置通知:@After
2) execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表]))
如果execution写成excution在applicationcontext.xml 中扫描包会出现问题。
value="execution(public * com.neuedu.bean.MyMathImpl.*(..))"
支持通配符 第一个*代表了任意的返回类型,第二*代表了该类下任意的方法,..代表任意的参数类型和个数。
最详细的切入点表达式:
execution(public int com.neuedu.aop.target.MathCalculatorImpl.add(int, int))
最模糊的切入点表达式:
execution (* *.*(..))
用@PointCut注解统一声明,然后在其它通知中引用该统一声明即可!
需要注意的是:权限是不支持写通配符的,当然你可以写一个*表示所有权限所有返回值!
3)通知方法的细节,参数
a).通知方法中有一个JoinPoint类型的参数
可以获取目标方法的签名,进而获取方法名
Signature signature = point.getSignature();
String name = signature.getName();
可以获取方法的参数,不过需要转换:
Object[] args = point.getArgs();
List<Object> asList = Arrays.asList(args);
b) 在返回通知中获取方法的返回值
[1]在@AfterReturning注解中添加returning属性
@AfterReturning (value="myPointCut()", returning= "result")
[2]在返回通知的通知方法中声明一个形参,形参名和returning属性的值一致
showReturnLog(JoinPoint joinPoint, Object result)
[3]在异常通知中获取异常对象
[1]在@ AfterThrowing注解中添加throwing属性
@AfterThrowing (value="myPointCut()",throwing= "throwable" )
[2]在异常通知的通知方法中声明一个形参,形参名和throwing属性值一致
showExceptinLog(JoinPoint joinPoint, Throwable throwable)
四、创建一个测试类:
public class IOCTest { private ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml"); @Test public void test() { /*Object bean = ioc.getBean("myMathImpl"); System.out.println(bean);*/ MyMath bean2 = ioc.getBean(MyMath.class); bean2.add(10, 2); } }
执行结果:
日志,前置通知,参数为:add方法为:[10, 2]
目标方法add执行了, 12
日志,后置通知
日志,返回置通知,结果为: 12
当出现异常:除法中一个数除以0 会出现异常
public class IOCTest { private ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml"); @Test public void test() { /*Object bean = ioc.getBean("myMathImpl"); System.out.println(bean);*/ MyMath bean2 = ioc.getBean(MyMath.class); bean2.div(10, 0); } }
执行结果为:
日志,前置通知,参数为:div方法为:[10, 0]
java.lang.ArithmeticException: / by zero
日志,后置通知