SpringAop--相关名词--xml配置实现aop--注解实现aop(当下主流)

我们若想把一些代码统一的放在某些类的方法中,就衍生出aop。

相关名词:

通知、增强处理(Advice):
就是你想要增加的功能,也就是上说的安全、事物、日志、(开启关闭事务、回滚事务…)等。你给先定义好,然后再想用的地方用一下。包含Aspect的一段处理代码.

连接点:
就是spring允许你是通知(Advice/增加功能)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。

切入点(Pointcut):
上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有十几个连接点了对吧,但是你并不想在所有方法附件都使用通知(使用叫织入,下面再说),你只是想让其中几个连接点,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。

切面(Aspect:
切面是通知和切入点的结合。现在发现了吧,没连接点什么事,链接点就是为了让你好理解切点搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。

织入(weaving 把通知切入到切入点的过程):
织入(weaving) 把切面应用到目标对象来创建新的代理对象的过程。

目标(target):
引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咋们织入切面。二自己专注于业务本身的逻辑。

引入(introduction):
允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗

配置实现aop:

xml配置:

   <bean id="logAspect" class="cn.itnls.aop.LogAspect"/>
   <aop:config>
      <aop:aspect ref="logAspect">
         <!--切入点 expression:表达式匹配要执行的方法,用来确定通知往哪写类哪些方法里切入。第一个*代表任何的返回值,.*.*(..)):impl包下的任何类的任何方法任何参数都切进去。-->
         <aop:pointcut id="logAspectPointCut" expression="execution(* cn.itnls.service.Impl.*.*(..))"/>
<!--         作用于方法开始之前-->
         <aop:before method="before" pointcut-ref="logAspectPointCut"/>
<!--         方法已经结束了-->
         <aop:after method="after" pointcut-ref="logAspectPointCut"/>
<!--         返回之后执行aspect代码,方法还未结束不能和around共存-->
         <aop:after-returning method="returning" pointcut-ref="logAspectPointCut"/>
         <aop:after-throwing method="throwing" pointcut-ref="logAspectPointCut"/>
<!--        把原来的代码覆盖,执行around相关代码,不能和returning共存, 用的少 -->
         <aop:around method="round" pointcut-ref="logAspectPointCut"/>
      </aop:aspect>
   </aop:config>

aop主类

public class LogAspect {

    public void before(){
        System.out.println("执行方法之前打印一条日志! -- 自定义形式");
    }

    public void after(){
        System.out.println("执行方法之后打印一条日志! -- 自定义形式");
    }

    public void round(){
        System.out.println("round打印一条日志! -- 自定义形式");
    }

    public void returning(){
        System.out.println("returning打印一条日志! -- 自定义形式");
    }

    public void throwing(){
        System.out.println("throwing打印一条日志! -- 自定义形式");
    }
}

测试方法

 @Test
    public void iocTest1(){
        AbstractApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("application.xml");
        IUserService iUserService  = applicationContext.getBean(IUserService.class);
        iUserService.findUserById(2);
    }

注解实现aop:

主类:

@Component
@Aspect
public class LogAspect {

    //方法执行前
    //若想让打了特定注解的方法上织入此通知,则:@Before("@annotation(该特定注解的全路径类名)")
    @Before("execution(* cn.itnls.service.Impl.*.*(..))")
    public void before(){
        System.out.println("执行方法之前打印一条日志! -- 自定义形式");
    }
//  方法执行后,有没有异常都会执行
    @After("execution(* cn.itnls.service.Impl.*.*(..))")
    public void after(){
        System.out.println("执行方法之后打印一条日志! -- 自定义形式");
    }
//环绕通知,会覆盖原有方法的内容
//    @Around("execution(* cn.itnls.service.Impl.*.*(..))")
//    public void round(){
//        System.out.println("round打印一条日志! -- 自定义形式");
//    }

//    返回通知,返回之后进行切入,有异常就不执行了
    @AfterReturning("execution(* cn.itnls.service.Impl.*.*(..))")
    public void returning(){
        System.out.println("returning打印一条日志! -- 自定义形式");
    }

//    发生异常会进行通知
    @AfterThrowing("execution(* cn.itnls.service.Impl.*.*(..))")
    public void throwing(){
        System.out.println("throwing打印一条日志! -- 自定义形式");
    }
}

xml配置中:

<aop:aspectj-autoproxy/>

测试方法和配置相同

Joinpoint的使用

通过此方式对注解进行灵活配置,注解可以加一些参数辅助横切.拿到连接点,并处理连接点相关的内容

自定义注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAnnotation {
    String value() default "show";
}

Aspect通知类:

@Component
@Aspect
public class LogAspect {

    //方法执行前
    //若想让打了特定注解的方法上织入此通知,则:@Before("@annotation(该特定注解的全路径类名)")
    @Before("@annotation(cn.itnls.annotation.LogAnnotation)")
    public void before(){
        System.out.println("执行方法之前打印一条日志! -- 自定义形式");
    }
//  方法执行后,有没有异常都会执行
    @After("@annotation(cn.itnls.annotation.LogAnnotation)")
    public void after(JoinPoint joinPoint){
        //获得代理对象
//        Object target = joinPoint.getTarget();
        //获得被代理对象
//        Object aThis = joinPoint.getThis();
        //
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);

        String value = annotation.value();
        System.out.println(value);
        System.out.println("执行方法之后打印一条日志! -- 自定义形式");
    }
//环绕通知,会覆盖原有方法的内容
//    @Around("execution(* cn.itnls.service.Impl.*.*(..))")
//    public void round(){
//        System.out.println("round打印一条日志! -- 自定义形式");
//    }

//    返回通知,返回之后进行切入,有异常就不执行了
    @AfterReturning("@annotation(cn.itnls.annotation.LogAnnotation)")
    public void returning(){
        System.out.println("returning打印一条日志! -- 自定义形式");
    }

//    发生异常会进行通知
    @AfterThrowing("@annotation(cn.itnls.annotation.LogAnnotation)")
    public void throwing(){
        System.out.println("throwing打印一条日志! -- 自定义形式");
    }
}

被自定义注解标注的方法:

@Controller
public class UserController {
    @Autowired
    private IUserService userService;

    @LogAnnotation("show-ssr")
    public void showUser(Integer id){
        System.out.println(userService.findUserById(id));
    }
}

结果:
执行方法之前打印一条日志! – 自定义形式
方法在执行
--------使用了--------
User{id=1, username=‘18’, password=‘15’}
returning打印一条日志! – 自定义形式
show-ssr
执行方法之后打印一条日志! – 自定义形式

环绕通知:

自己写的方法可以被切入的内容“环绕”起来,只要写了环绕通知,其他通知,包括自定义被通知的方法,都被覆盖掉了。

若想在方法前后加内容,并且内容有关联,就用环绕通知

先把其他通知都注释掉:

@Around("execution(* cn.itnls.service.Impl.*.*(..))")
    public void round(ProceedingJoinPoint pjp){
        System.out.println("round打印一条日志! -- 自定义形式");
        try {
            pjp.proceed(); //★执行目标方法
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("after");
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值