AspectJ简介
- AspectJ是一个基于Java语言的AOP框架
- Spring2.0以后新增了对AspectJ切点表达式支持
- @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
- 新版本Spring框架,建议使用AspectJ方式来开发AOP
- 主要用途:自定义开发
AspectJ通知类型
aop联盟定义通知类型,具有特性接口,必须实现,从而确定方法名称。
aspectj 通知类型,只定义类型名称,以及方法格式。
- before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行 - afterReturning:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。 - around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行
必须手动执行目标方法 - afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行 - after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常
切入点表达式
- 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
使用xml文件来实现切入
- 导包
aopalliance-1.0.0.jar | AOP联盟规范 |
---|---|
spring-aspects-3.2.0.RC2.jar | aspectj实现 |
spring-aop-3.2.0.jar | AOP实现 |
aspectj.weaver-1.6.jar | 织入 |
代码
- 切面类
package spring.aspect;
/**
* 切面类:增强代码与切入点的结合
*/
public class MyAspect{
public void myBefore()
{
System.out.println("前置通知...");
}
}
- 目标类
package spring.service.impl;
import org.springframework.stereotype.Service;
import spring.service.UserService;
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void updateUser() {
System.out.println("更新用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
- 配置beans.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.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
"
>
<!--配置UserService-->
<bean id="userService" class="spring.service.impl.UserServiceImpl"/>
<!--配置切面对象-->
<bean id="myAspect" class="spring.aspect.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切面-->
<aop:aspect ref="myAspect">
<!--切入点-->
<aop:pointcut id="myPointcut" expression="execution(* spring.service.impl.UserServiceImpl.*(..))"/>
<!--配置一个前置通知-->
<aop:before method="myBefore" pointcut-ref="myPointcut"></aop:before>
</aop:aspect>
</aop:config>
</beans>
- 测试类
@Test
public void test5()
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
UserService service = (UserService) context.getBean("userService");
service.deleteUser();
}
}
- 运行结果
使用注解来实现切入
- 配置beans.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.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
"
>
<!--扫描注解位置-->
<context:component-scan base-package="spring"></context:component-scan>
<!--AOP注解生效-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 使用注解来声明service和切面
package spring.service.impl;
import org.springframework.stereotype.Service;
import spring.service.UserService;
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void updateUser() {
System.out.println("更新用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
package spring.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 切面类:增强代码与切入点的结合
*/
@Component
@Aspect
public class MyAspect {
//声明一个公共切入点
@Pointcut("execution(* spring.service.impl.UserServiceImpl.*(..))")
public void myPointcut() {}
//声明前置通知
@Before("myPointcut()")
public void myBefore()
{
System.out.println("前置通知...");
}
//声明后置通知
@AfterReturning(value = "myPointcut()", returning = "ret")
public void myAfterReturnning(Object ret){
System.out.println("后置通知...");
}
//声明环绕通知
@Around(value = "myPointcut()")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知前...");
Object obj = pjp.proceed();//放行
System.out.println("放行");
System.out.println("环绕通知后...");
return obj;
}
//声明异常通知
@AfterThrowing(value = "myPointcut()", throwing = "e")
public void myAfterThrowing(Throwable e)
{
System.out.println("异常通知...");
}
//声明最终通知
@After(value = "myPointcut()")
public void myAfter(){
System.out.println("最终通知...");
}
}
- 测试类
@Test
public void test1()
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService service = (UserService) context.getBean("userService");
service.deleteUser();
}
- 运行结果
注解总结
- @Aspect 声明切面,修饰切面类,从而获得 通知。
- @Before 前置
- @AfterReturning 后置
- @Around 环绕
- @AfterThrowing 抛出异常
- @After 最终
- @PointCut ,修饰方法 private void xxx(){} 之后通过“方法名”获得切入点引用