AOP(Aspect Oriented Programming)面向切面的编程
切面通过通知(advise),切点(Pointcut),织入点(Join points)来描述。
简单点说就是对一个方法(切点)执行的特殊时间点插入一些处理(增强/通知)。
例如BookService的showBookInfo方法,我们在该方法的Before,After,Around,AfterReturning,AfterThrowing等特殊点插入执行一些特殊的处理。
几个术语:
连接点(Join point):能够被拦截的地方
切点(Pointcut):处理的方法。即上面提到的showBookInfo方法
增强/通知(advice):添加到切点的处理。上面提到的Before, After, AfterReturning, AfterThrowing
织入(Weaving):将增强/通知添加到具体类的切点的过程
切面(Aspect):有切点和增强/通知组成
引入(Introduction):引入新的类和方法增强Bean的功能
BookService.java
public interface BookService {
public void showBookInfo(Book book);
}
BookServiceImpl.java
@Service
public class BookServiceImpl implements BookService {
@Override
public void showBookInfo(Book book) {
if (book == null) {
throw new RuntimeException("null object");
}
System.out.print("Bookid:"+ book.getID());
System.out.print("\t BookName:" + book.getName());
System.out.println("\t Author:" + book.getAuthor());
}
}
showBookInfo就是我们的切点
BookServiceAspect.java
@Aspect
public class BookServiceAspect {
@Pointcut("execution(* com.springboot.aop.test.service.BookServiceImpl.showBookInfo(..))")
public void pointCut() {
}
@Before("pointCut()")
public void before() {
System.out.println("-------before.........");
}
@Around("pointCut()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("-------around before.........");
pjp.proceed();
System.out.println("-------around after.........");
}
@After("pointCut()")
public void after() {
System.out.println("-------after.........");
}
@AfterReturning("pointCut()")
public void afterReturning() {
System.out.println("-------afterReturning.........");
}
@AfterThrowing("pointCut()")
public void afterThrowing() {
System.out.println("-------afterThrowing.........");
}
}
对增强/通知添加了对应的处理。
- execution表示执行时拦截规则
- 任意返回类型
- 包名
- 方法名
- (..)表示任意参数
BookAOPController.java
@RestController
@RequestMapping("/book")
public class BookAOPController {
@Autowired
private BookService bookService = null;
@ResponseBody
@GetMapping("/showbookinfo")
public Book showBookInfo(@RequestParam String bookID, @RequestParam String bookName, @RequestParam String author) {
Book book = null;
if (bookID != null) {
book = new Book();
book.setID(bookID);
book.setName(bookName);
book.setAuthor(author);
}
bookService.showBookInfo(book);
return book;
}
}
SpringbookAopApplication.java
@SpringBootApplication
public class SpringbootAopApplication {
@Bean(name="bkServiceAspect")
public BookServiceAspect initAspect() {
return new BookServiceAspect();
}
public static void main(String[] args) {
SpringApplication.run(SpringbootAopApplication.class, args);
}
}
测试
可以看到我们的切点对应的增强/通知中的处理都执行了
引入(Introduction)
引入的作用简单来说就是可以在不修改原有类的代码的情况下新增处理的方法。对于我们使用第三方的类但希望增加我们的处理的情况适用。
对于上面的BookService我们可以通过“引入”增加一个判断Book信息是否有效的方法validate。具体的实现参照以下步骤
新增接口
BookInfoValidator.java
public interface BookInfoValidator {
public boolean validate(Book book);
}
实现validate
public class BookInfoValidatorImpl implements BookInfoValidator{
@Override
public boolean validate(Book book) {
System.out.println("Introduction:"+BookInfoValidator.class.getSimpleName());
if ((book.getID()!=null)&&(book.getID().trim().length()>0)&&
(book.getName()!=null)&&(book.getName().trim().length()>0)&&
(book.getAuthor()!=null)&&(book.getAuthor().trim().length()>0)) {
return true;
}
return false;
}
}
引入
@Aspect
public class BookServiceAspect {
//Introduction BookInfoValidator to BookServiceImpl
@DeclareParents(
value= "com.springboot.aop.test.service.BookServiceImpl",
defaultImpl=com.springboot.aop.test.validator.BookInfoValidatorImpl.class)
public BookInfoValidator bookInfoValidator;
...
}
value指明要进行增强的类
defaultImpl指明实现的class
调用
@ResponseBody
@RequestMapping("/bookvalidate")
public Book bookValidate(String bookID, String bookName, String author) {
Book book = null;
book = new Book();
book.setID(bookID);
book.setName(bookName);
book.setAuthor(author);
BookInfoValidator bkValidator = (BookInfoValidator) bookService;
if (bkValidator.validate(book)) {
bookService.showBookInfo(book);
return book;
} else {
System.out.println("BookValidator failed");
return null;
}
}
测试
当请求中bookID为空时报错
通知获取参数
在通知中也可以传入参数,只需在pointCut()后添加&&args(arg1,arg2...)
之前通知Before处改为如下
@Before("pointCut() && args(book)")
public void beforeParam(JoinPoint point, Book book) {
Object[] args = point.getArgs();
System.out.println("-------before.........");
System.out.println("args:"+args.length);
}
传入参数Book
示例代码在SpringbootAOP
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。