spring aop,面向切面编程;
1,用途:在日志,登陆等重复无关业务逻辑的部分抽象出来;
2,原理:java动态代理;
java.lang.reflect.Proxy;
切面:需要执行的代码x(),比如插入的日志代码;
切入点:需要插入的位置,比如add()方法前面,后面....
通知:一个普通的类->有特定功能的类:
可以通过a,继承各种类;b,实现接口;3,注解,4,配置;
通知:
1,前置通知,在执行add()方法前执行;
2,后置通知,在执行add()方法正常执行后执行;
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;