在新版本的Spring
框架中使用AspectJ
开发AOP
AspectJ是什么
概念:
基于Java
语言的AOP
框架,扩展了Java
语言
使用AspectJ开发AOP的方式
-
基于
XML
的声明式AspectJ
-
基于
Annotation
的声明式AspectJ
基于AspectJ XML开发Spring AOP
具体是指:
通过Spring
配置文件的方式来定义切面、切入点、通知。
具体实现:
所有的切面和通知必须定义在<aop:config>
元素中
步骤:
-
导入
Spring aop
命名空间 -
定义切面
-
定义切入点
-
定义通知
导入Spring aop命名空间
定义切面<aop:aspect>
作用:
把定义好的Bean
转换成切面Bean
。所以使用该元素需要先定义一个普通Spring Bean
示例:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<!--
id用来定义该切面唯一表示名称
ref用于引用普通的Spring Bean
-->
定义切入点<aop:pointcut>
作用:
定义一个切入点
-
作为
<aop:config>
元素的子元素---->表示该切入点是全局切入点 -
作为
<aop:aspect>
元素的子元素--->表示该切入点只对当前切面有效
示例:
<aop:config>
<aop:pointcut id="myPointCut"
expression="execution(* com.junkingboy.service.*.*(..))"/>
</aop:config>
<!--
id用于指定切入点的唯一标识名称
execution指定切入点关联的切入点表达式
-->
execution
格式:
execution(modifiers-pattern returning-type-pattern declaring-type-pattern name-pattern(param-pattern)throws-pattern)
-
returning-type-pattern、name-pattern、param-pattern 是必须的,其它参数为可选项。
-
modifiers-pattern:指定修饰符,如 private、public。
-
returning-type-pattern:指定返回值类型,
*
表示可以为任何返回值。如果返回值为对象,则需指定全路径的类名。 -
declaring-type-pattern:指定方法的包名。
-
name-pattern:指定方法名,
*
代表所有,set*
代表以 set 开头的所有方法。 -
param-pattern:指定方法参数(声明的类型),
(..)
代表所有参数,(*)
代表一个参数,(*,String)
代表第一个参数可以为任何值,第二个为 String 类型的值。 -
throws-pattern:指定抛出的异常类型。
定义通知
具体可定义五种类型的advice
:
<aop:aspect id="" ref="">
<!-- 前置通知 -->
<aop:before pointcut-ref="" method="" />
<!-- 后置通知 -->
<aop:after-returning pointcut-ref="" method="" />
<!-- 环绕通知 -->
<aop:around pointcut-ref="" method="" />
<!-- 异常通知 -->
<aop:after-throwing pointcut-ref="" method="" />
<!-- 最终通知 -->
<aop:after pointcut-ref="" method="" />
...
</aop:aspect>
理解:
本质上就是通过xml
对各个接口、类、Bean
对象实现调用而非代码上的强制调用。
定义loggin
类:
public class Logging {
/**
* 前置通知
*/
public void beforeAdvice() {
System.out.println("前置通知");
}
/**
* 后置通知
*/
public void afterAdvice() {
System.out.println("后置通知");
}
/**
* 返回后通知
*/
public void afterReturningAdvice(Object retVal) {
System.out.println("返回值为:" + retVal.toString());
}
/**
* 抛出异常通知
*/
public void afterThrowingAdvice(IllegalArgumentException ex) {
System.out.println("这里的异常为:" + ex.toString());
}
}
ORM的对象:
package net.biancheng;
public class Man {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void throwException() {
System.out.println("抛出异常");
throw new IllegalArgumentException();
}
}
Bean
xml
启动类:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Man man = (Man) context.getBean("man");
man.getName();
man.getAge();
man.throwException();
}
}
AspectJ基于注解开发AOP
为了防止xml
文件过于臃肿,AspectJ 框架为 AOP 开发提供了一套注解。AspectJ 允许使用注解定义切面、切入点和增强处理,Spring 框架可以根据这些注解生成 AOP 代理。
Annotation
注解介绍:
名称 | 说明 |
---|---|
@Aspect | 用于定义一个切面。 |
@Pointcut | 用于定义一个切入点。 |
@Before | 用于定义前置通知,相当于 BeforeAdvice。 |
@AfterReturning | 用于定义后置通知,相当于 AfterReturningAdvice。 |
@Around | 用于定义环绕通知,相当于MethodInterceptor。 |
@AfterThrowing | 用于定义抛出通知,相当于ThrowAdvice。 |
@After | 用于定义最终final通知,不管是否异常,该通知都会执行。 |
@DeclareParents | 用于定义引介通知,相当于IntroductionInterceptor(不要求掌握)。 |
@AspectJ
注解的两种方法:
使用@Configuration和@EnableAspectJAutoProxy
注解:
@Configuration
@EnableAspectJAutoProxy
public class Appconfig{
}
基于xml
配置:
<aop:aspectj-autoproxy>
定义切面@Aspect
使用Aspect
注解:
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AspectModule {
}
在xml
中配置:
<bean id = "myAspect" class = "类路径">
...
</bean>
定义切入点@Pointcut
使用Aspect
注解*
// 要求:方法必须是private,返回值类型为void,名称自定义,没有参数
@Pointcut("execution(*包名..*.*(..))")
private void myPointCut() {
}
在xml
中配置:
<aop:pointcut expression="execution(*包名..*.*(..))" id="myPointCut"/>
定义通知advice
上面说到的五种类型,以before
作为示例:
@Before("方法名")
public void beforeAdvice(){
...
}
/* 表示在某个方法之后调用 */