spring不仅可以通过使用xml标签的方式实现,生成切面,还可以通过注解方式声明切面。
基于注解方式声明切面,实现AOP编程
采用注解方式实现(Annotation)步骤:
- 先在beans.xml文件中引用aop schema,然后启动代理自动生成的扫描配置
- 拦截器进行注解开发
- 拦截器和service都要在beans.xml文件中配置
xml文件注解详细表:
@Before | 在被代理对象的方法前先调用,属于前置通知。 |
@AfterReturning | 在被代理对象的方法正常返回后调用,属于返回通知(也等于后置通知)如果发生异常则不会被调用 |
@Around | 在被代理对象的方法封装起来,并用环绕通知取代它,属于环绕通知,它将覆盖原有的方法,但是允许你通过反射调用原有方法。环绕通知是Spring AOP中最强大的通知,它可以同时实现前置和后置的通知,它保留了调度被代理对象原有方法的功能,所以它强大,又灵活。这个通知里有一个参数ProceedingJoinPoint,是Spring提供的一个参数,使它可以反射连接点。当环绕通知使用proceed()方法后会先调用前置通知,然后反射切点方法,最后就是后置通知和返回(或者异常)通知。 |
@AfterThrowing | 在被调用对象的方法抛出异常后调用,属于异常通知,要求被代理对象的方法执行过程中产生异常 |
@After | 在被代理对象的方法后调用,属于后置通知 |
配置拦截器
使用注解方法进行aop编程,必须要有一个私有的,无返回值的、没有方法体的方法:
private void add() {}//这个方法要求私有,不能有返回值,不能有参数
package interceptor;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 配置一个拦截器
*/
@Aspect
public class ExtendFilter {
private Logger log = Logger.getLogger("service.BookServiceImpl");
@Pointcut("execution(* service..*.*(..))")
private void add() {}//这个方法要求私有,不能有返回值,不能有参数
//("execution(* service..*.*(..))")
//括号里面的参数表示:切入点是service包及其子包的所有方法,不管有没有返回值
/**
* 对访问权限进行控制的方法 前置通知
*/
@Before("add()")
public void access()
{
log.log(Level.INFO, "前置通知:在调用方法前输出");
}
/**
* 进行异常处理的方法 异常通知
*/
public void handleException()
{
log.log(Level.INFO,"异常通知:出现异常时输出");
}
/**
* 获取ip地址的方法 后置通知
*/
@After("add()")
public void getIp()
{
log.log(Level.INFO,"后置通知:在调用方法后输出");
}
/**
* 环绕通知输出,那么这个方法很特殊,需要获取目标对象的相关参数
*/
@Around("add()")
public Object writeLog(ProceedingJoinPoint joinpoint)
{
log.log(Level.INFO,"环绕通知(前):---------------");
Object obj=null;
try {
obj=joinpoint.proceed();//调用目标对象方法
} catch (Throwable e) {
e.printStackTrace();
}
log.log(Level.INFO,"环绕通知(后):---------------");
return obj;
}
}
配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 启动代理自动生成的扫描配置 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 目标对象 -->
<bean id="bookService" class="service.BookServiceImpl"></bean>
<!-- 拦截器 -->
<bean id="extendFilter" class="interceptor.ExtendFilter"></bean>
</beans>
编写目标对象的接口
package service;
public interface BookServiceIfac {
void addBook(String name);
}
编写目标类,并且事项刚刚写的接口
package service;
public class BookServiceImpl implements BookServiceIfac {
@Override
public void addBook(String name)
{
System.out.println("添加了图书,书名为 :"+name);
}
}
编写测试类
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.BookServiceIfac;
import service.ProductService;
public class Test {
public static void main(String[] args) {
ApplicationContext act = new ClassPathXmlApplicationContext("beans.xml");
BookServiceIfac bookService = (BookServiceIfac) act.getBean("bookService");
bookService.addBook("水浒传!");
}
}
查看控制台,看输出结果: