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;