spring aop,面向切面編程;java
1,用途:在日誌,登錄等重複無關業務邏輯的部分抽象出來;web
2,原理:java動態代理;spring
java.lang.reflect.Proxy;
切面:須要執行的代碼x(),好比插入的日誌代碼;數據庫
切入點:須要插入的位置,好比add()方法前面,後面....express
通知:一個普通的類->有特定功能的類: 編程
能夠經過a,繼承各類類;b,實現接口;3,註解,4,配置;session
通知: app
1,前置通知,在執行add()方法前執行;ide
2,後置通知,在執行add()方法正常執行後執行;url
3,環繞通知:能夠是前置|後置|異常時執行;
4,異常通知:程序異常才執行;
在applicationContext.xml配置aop
<bean id="logBefore" class="xxx.xxx.xxx">
</bean>
<!--將 切入點 和 通知 進行關聯-->
<aop:config>
<aop:pointcut expression="execution(public void org.service.Student.addStudent(Student stu))">
<aop:advisor advice-ref="logBefore" poincut-ref="pointcut"/>
</aop:config>
<!--將通知歸入springIOC容器--> <bean id="notice" class=""></bean> <aop:config> <!--切入點,須要執行代碼的地方--> <aop:pointcut id="pointcut" expression="execution(public * xx.xxx.function(paramtype))"/> <!--須要執行的代碼 --> <aop:advisor advice-ref="notice" pointcut-ref="pointcut"/> </aop:config>
說明:在任何addStudent方法前面,執行logBefore方法;
使用步驟:
1,通知類,普通實現通知接口;
2,業務類,業務方法:
3,配置: 將通知類,業務類歸入springIOC容器,xml中配置aop:config關聯切入點和通知類
環繞通知:(本質是攔截器)
public class LogAround implements MethodInterceptor { public Object invoke(MethodInvocation methodInvocation) throws Throwable { Object result=null; // 目標方法返回值 try{ //前置通知執行代碼 result = methodInvocation.proceed(); //後置通知執行代碼 }catch (Exception e) { //異常通知執行代碼 } return result; } }
配置:
<bean id="LogAround" class="com.maotu.control.LogAround"></bean> <aop:config> <!--切入點,須要執行代碼的地方--> <aop:pointcut id="pointcut2" expression="execution(public * xx.xxx.addStudent(paramtype))"/> <!--須要執行的代碼 --> <aop:advisor advice-ref="LogAround" pointcut-ref="pointcut2"/> </aop:config>
環繞通知能夠獲取目標方法的一切控制權:是否執行,執行前代碼,執行後代碼,執行返回值更改;
二,使用註解實現通知,aop
開啓註解:
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
1,設置掃描器:掃描註解所在的包
<context:component-scan base-package=""></context:component-scan>
2,配置: 將通知類,業務類歸入springIOC容器,xml中配置aop:config關聯切入點和通知
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; @Component("logAroundAnno") @Aspect public class LogAroundAnno { @Before("execution(public * addStudent(..))") //屬性:定義切點 public void myBefore(JoinPoint jp) { System.out.println("基於註解的前置通知,目標對象:"+jp.getTarget()+",方法名:"+jp.getSignature().getName()+",參數列表:"+ Arrays.toString(jp.getArgs())+";"); } @AfterReturning(pointcut = "execution(public * addStudent(..))",returning = "returnValue") //屬性:定義切點 public void myAfter(JoinPoint jp,Object returnValue) { System.out.println("基於註解的後置通知,目標對象:"+jp.getTarget()+",方法名:"+jp.getSignature().getName()+",參數列表:"+ Arrays.toString(jp.getArgs())+";返回值:"+returnValue); } //只捕獲特定異常 @AfterThrowing(pointcut = "execution(public * addStudent(..))",throwing="e") public void myException(JoinPoint jp,NullPointerException e){ System.out.println("基於註解的異常通知: 只捕獲空指針異常:e "+e.getMessage()); } @Around("execution(public * addStudent(..))") //環繞通知 public void myAround(ProceedingJoinPoint jp){ try{ //前置通知 jp.proceed(); //後置通知 }catch (Throwable e) { //異常通知 }finally{ //最終通知 } } @After("execution(public * addStudent(..))") public void MyAfter(){ System.out.println("基於註解的最終通知"); } }
例子:登錄驗證
環境:intelli idea 2018+java 1.8
1,新建spring boot工程:包含登錄頁面/login; 主頁/index
2,新建攔截器類:
import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Slf4j @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("----登錄攔截器----"); if(request.getSession().getAttribute("username")==null) { response.sendRedirect("/login"); return false; } return true; } }
攔截器繼承:HandlerInterceptor ,重載PreHandle方法;若是session中沒有用戶名,則進入登錄頁面;
3,新建登錄適配器:
import com.maotu.gameagent.interceptor.LoginInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @SpringBootConfiguration public class LoginAdapt implements WebMvcConfigurer{ @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login**"); } }
對全部url進行攔截,對登錄頁面不攔截;
3,請求映射:
@RequestMapping(value = "/login") public String login(HttpServletRequest request){ String userName = request.getParameter("username"); if(userName!=null) { request.getSession().setAttribute("username",userName); return "/agent/index"; } return "/login"; } @RequestMapping("/logout") public String logout(HttpServletRequest request) { try { request.getSession().invalidate(); request.logout(); } catch (ServletException e) { e.printStackTrace(); } return "/login"; }
登錄用戶,到數據庫中驗證後,session賦值;退出後清空session。
註解形式依賴注入:
1,自動裝配,根據類型
@Service("aaa") @Autowired
2,自動裝配,根據名稱裝配,
@Repository("stuDao") @Autowired @Qualifier("stuDao") private IstudentDao studentDao;