- AOP对OOP的补充,而不是替代
- OOP的核心单位是类,而AOP则是切面
- 典型的例子包括日志,验证,事务管理
- 优点(1)使开发人员集中关注于系统的核心业务逻辑 (2)更利于创建松散的,可复用的,可扩展的软件系统
切面:切点和通知
五种通知类型(增强类型)
1. 前置和后置指的是时间;
2.最终通知相当于finally通知,都会执行
五种通知的接口:
(1)前置通知
public class BeforeAdvices implements MethodBeforeAdvice{
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("切面方法对象是"+arg0);
System.out.println("切面方法参数列表是"+Arrays.asList(arg1));
System.out.println("切面方法应用的对象是"+arg2);
System.out.println("前置通知执行");
}
(2)后置通知
public class AfterReturningsAdvice implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置通知执行");
System.out.println("执行结果是"+returnValue);//返回结果
}
(3)异常通知
public class ThrowAdvice implements ThrowsAdvice{
//注意异常类型
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("异常信息是"+ex.getMessage());
System.out.println("异常通知执行");
}
(4)最终通知
public class Afters implements AfterAdvice{
}
(5)环绕通知
public class Arounds implements MethodInterceptor{
//invoke调用 MethodInvocation.proceed得到一个Object对象
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("前置通知执行中");
Object proceed = arg0.proceed();
System.out.println("环绕通知的结果"+proceed);
System.out.println("后置通知执行中");
return proceed;
}
实现AOP的方法:(三种)
(1)使用Schema-based方式实现Aop
<!-- 使用Schema-based方式实现Aop -->
<bean id="calculateImpl" class="com.xxx.schema.CalculateImpl"></bean>
<!-- 实例化通知对象,把通知类注入到IOC容器中 ,在切面中引用 -->
<bean id="before" class="com.xxx.schema.BeforeAdvices"></bean>
<!-- 注意:最终通知实现类没有重写方法 -->
<!-- <bean id="after" class="com.xxx.schema.Afters"></bean> -->
<bean id="throw" class="com.xxx.schema.ThrowAdvice"></bean>
<bean id="around" class="com.xxx.schema.Arounds"></bean>
<bean id="afterreturn" class="com.xxx.schema.AfterReturningsAdvice"></bean>
<!-- 配置AOP,把切面织入到目标对象 -->
<aop:config>
<!-- 配置切点,*是通配符,方法参数(..) -->
<aop:pointcut expression="execution(public int com.xxx.schema.CalculateImpl.*(..))" id="point"/>
<!-- 配置通知 -->
<aop:advisor advice-ref="before" pointcut-ref="point"/>
<!-- <aop:advisor advice-ref="after" pointcut-ref="point"/> -->
<aop:advisor advice-ref="throw" pointcut-ref="point"/>
<aop:advisor advice-ref="around" pointcut-ref="point"/>
<aop:advisor advice-ref="afterreturn" pointcut-ref="point"/>
</aop:config>
配置切点表达式,语法
<aop:pointcut expression=“execution(public int com.xxx.schema.CalculateImpl.*(…))” >
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
问号表示当前项可以有也可以没有,其中各项的语义如下:
1. modifiers-pattern:方法的可见性,如public,protected;
2. ret-type-pattern:方法的返回值类型,如int,void等;
3. declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
4. name-pattern:方法名类型,如buisinessService();
5. param-pattern:方法的参数类型,如java.lang.String;
6. throws-pattern:方法抛出的异常类型,如java.lang.Exception;
(2)AspectJ之XML文件方式实现AOP
public class MyAspect {
//在Java文件中选择类名,然后Copy Qualified Name;
//怎样访问当前连接点的细节
public void one(JoinPoint jp){
String name = jp.getSignature().getName();
Object[] args = jp.getArgs();
System.out.println(name+"前置通知执行"+",参数列表是"+Arrays.asList(args));
}
public void two(JoinPoint jp,Object re){
String name = jp.getSignature().getName();
System.out.println("后置通知执行的返回结果是"+re);
}
public void three(JoinPoint jp,Exception ex){
System.out.println("异常通知执行的异常信息为"+ex);
}
public void four(){
System.out.println("最终通知执行");
}
public Object five(ProceedingJoinPoint pjp){
Object[] args = pjp.getArgs();
String name = pjp.getSignature().getName();
Object result=null;
try {
System.out.println(name+"环绕准备就绪,参数列表是:"+Arrays.asList(args));
System.out.println("前置通知执行");
result = pjp.proceed();
System.out.println(name+"的返回结果是:"+result);
System.out.println("后置通知执行");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("异常通知执行");
}finally{
System.out.println(name+"环绕执行完毕,参数列表是:"+Arrays.asList(args));
System.out.println("最终通知执行");
}
return result;
}
}
<bean id="calculateImpl" class="com.xxx.aspectj.xml.CalculateImpl"></bean>
<bean id="aspects" class="com.xxx.aspectj.xml.MyAspect" />
<!-- 配置切面 -->
<aop:config>
<aop:aspect id="aspect" ref="aspects">
<aop:pointcut expression="execution(* com.xxx.aspectj.xml.CalculateImpl.add(..)) " id="pointcut"/>
<aop:around method="five" pointcut-ref="pointcut" />
<!-- <aop:after-returning method="two" pointcut-ref="pointcut" returning="re"/>
<aop:before method="one" pointcut-ref="pointcut" />
<aop:after-throwing method="three" pointcut-ref="pointcut" throwing="ex"/>
<aop:after method="four" pointcut-ref="pointcut" /> -->
</aop:aspect>
</aop:config>
(3)AspectJ之注解方式实现AOP
@Component
@Aspect
//通过@Order(*)标注指定切面优先级,*整数数值越小,优先级越高
public class MyAspect {
//定义切点
@Pointcut("execution(* com.xxx.aspectj.annotation.CalculateImpl.*(..))")
public void pointcut(){
}
@Before("pointcut()")
public void beforeone(JoinPoint jp){
String name = jp.getSignature().getName();
Object[] args = jp.getArgs();
System.out.println(name+"前置通知1执行"+",参数列表是"+Arrays.asList(args));
}
@Before("execution(* com.xxx.aspectj.annotation.CalculateImpl.*(..))")
public void beforefive(JoinPoint jp){
String name = jp.getSignature().getName();
Object[] args = jp.getArgs();
System.out.println(name+"前置通知2执行"+",参数列表是"+Arrays.asList(args));
}
@After("execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))")
public void four(){
System.out.println("最终通知执行");
}
@AfterReturning(pointcut="execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))",returning="re")
public void two(JoinPoint jp,Object re){
String name = jp.getSignature().getName();
System.out.println(name+"后置通知执行的返回结果是"+re);
}
@AfterThrowing(pointcut="execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))",throwing="ex")
public void three(JoinPoint jp,Exception ex){
System.out.println("异常通知执行的异常信息为"+ex);
}
@Around("execution(public int com.xxx.aspectj.annotation.CalculateImpl.*(..))")
public Object five(ProceedingJoinPoint pjp){
Object[] args = pjp.getArgs();
String name = pjp.getSignature().getName();
System.out.println(name+"环绕前置就绪,参数列表是:"+Arrays.asList(args));
Object result=null;
try {
result = pjp.proceed();
System.out.println(name+"的环绕返回结果是:"+result);
} catch (Throwable e) {
e.printStackTrace();
System.out.println("异常通知执行");
}finally{
System.out.println(name+"环绕后置执行完毕,参数列表是:"+Arrays.asList(args));
}
return result;
}
}
<!-- spring不自动寻找带注解的类,需要告诉哪些包中存在带注解的类 -->
<context:component-scan base-package="com.xxx.aspectj.annotation"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
测试
public static void main(String[] args) {
//加载配置文件
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext2.xml");
CalculateImpl cal=(CalculateImpl) ac.getBean("calculateImpl");
System.out.println(cal.add(3, 3));
}