面向切面編程:把邏輯代碼和處理瑣碎事務(wù)的代碼分離開,以便能夠分離復(fù)雜度。
1.連接點(Joinpoint)
2.切點(Pointcut)
3.增強(Advice)
Before advice
After returning advice
After throwing advice
After(finally) advice
Around advice
4.目標對象(Target)
5.引入(Introduction)
6.織入(Weaving)
7.代理(PRoxy)
8.切面(aspect)
更清晰的代碼邏輯,業(yè)務(wù)邏輯只關(guān)注自己本身,不用去管瑣碎的事情,比如:安全,日志,事務(wù)等等。
可以減少代碼量
想了解概念的同學(xué)可以去百度或者先看下面的demo 再理解
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.6</version></dependency><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.6</version></dependency>這里我只提供切面需要的依賴
如果不懂maven的同學(xué) 可以先看本站的教程
// 接口public interface IUserDao { void save(Person person);}@Component // 加入容器public class UserDao implements IUserDao{ @Override public void save(Person person) { System.out.println("-----核心業(yè)務(wù):保存!!!------"); }}public class Person { private String name; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; }}<?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:p="http://www.springframework.org/schema/p" 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="net.begincode.aop_anno"></context:component-scan> <!-- 開啟動態(tài)代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/></beans>@Component@Aspect // 指定當前類為切面類public class Aop { // 指定切入點表達式: 攔截哪些方法; 即為哪些類生成代理對象 @Pointcut("execution(* net.begincode.aop_anno.*.*(..))") public void pointCut_(){ } // 前置通知 : 在執(zhí)行目標方法之前執(zhí)行 @Before("pointCut_()") public void begin(){ System.out.println("開始事務(wù)/異常"); } // 后置/最終通知:在執(zhí)行目標方法之后執(zhí)行 【無論是否出現(xiàn)異常最終都會執(zhí)行】 @After("pointCut_()") public void after(){ System.out.println("提交事務(wù)/關(guān)閉"); } // 返回后通知: 在調(diào)用目標方法結(jié)束后執(zhí)行 【出現(xiàn)異常不執(zhí)行】 @AfterReturning("pointCut_()") public void afterReturning() { System.out.println("afterReturning()"); } // 異常通知: 當目標方法執(zhí)行異常時候執(zhí)行此關(guān)注點代碼 @AfterThrowing("pointCut_()") public void afterThrowing(){ System.out.println("afterThrowing()"); } // 環(huán)繞通知:環(huán)繞目標方式執(zhí)行 @Around("pointCut_()") public void around(ProceedingJoinPoint pjp) throws Throwable{ Object[] objs = pjp.getArgs(); Person p = (Person) objs[0]; System.out.println(p.getName()); System.out.println("環(huán)繞前...."); pjp.proceed(); // 執(zhí)行目標方法 System.out.println("環(huán)繞后...."); } }applicationContext ac = new ClassPathXmlApplicationContext("net/begincode/aop_anno/bean.xml");@Testpublic void testApp() { IUserDao userDao = (IUserDao) ac.getBean("userDao"); System.out.println(userDao.getClass());//$Proxy001 Person person = new Person(); person.setName("abc"); person.setSex("man"); userDao.save(person);}輸出:
class com.sun.proxy.$Proxy15abc環(huán)繞前....開始事務(wù)/異常-----核心業(yè)務(wù):保存!!!------環(huán)繞后....提交事務(wù)/關(guān)閉afterReturning()如果目標對象有實現(xiàn)接口,spring會自動選擇"JDK代理"
如果目標對象沒有實現(xiàn)接口,spring就會使用"cglib"代理
AOP的應(yīng)用很廣泛 功能很強大 可以做:安全,日志,事務(wù)等等。
這里介紹的只是最基本使用方法
參考文獻:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
在begincode 問答系統(tǒng)中 我們利用切面去攔截controller,使指定的入?yún)⒈粩r截
@Aspect@Componentpublic class RequestAspect { @Pointcut("execution(* net.begincode.controller.*.*(..))") public void pointCut_() { } @Around("pointCut_()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Object[] objects = proceedingJoinPoint.getArgs(); for (int i = 0; i < objects.length; i++) { if (objects[i] instanceof ProblemLabelParam) { ProblemLabelParam problemLabelParam = (ProblemLabelParam) objects[i]; problemLabelParam.check(); } } return proceedingJoinPoint.proceed(); }}攔截所有從controller進去的參數(shù) 并且驗證有沒有 ProblemLabelParam 類型的參數(shù)
如果有的話,則調(diào)用其中的check方法驗證傳入的參數(shù)是否有異常
部分代碼如下:
public class ProblemLabelParam extends Param{ .... @Override public void check() { checkNotEmpty(problem.getContent(),ProblemResponseEnum.PROBLEM_ADD_ERROR); checkNotEmpty(problem.getTitle(),ProblemResponseEnum.PROBLEM_ADD_ERROR); } .... }我們規(guī)定入?yún)ο蟊仨毴坷^承Param類 不能使用原有的model直接進入方法
并且實現(xiàn)抽象的check方法
public abstract class Param { public abstract void check(); public void checkNotNull(Object value, ResponseEnum status) { checkArgs(value != null, status); } public void checkNotEmpty(String value, ResponseEnum status) { checkArgs(StringUtils.isNotBlank(value), status); } public void checkArgs(boolean success, ResponseEnum status) { if (!success) { throw new BizException(status); } }}
新聞熱點
疑難解答