详解SpringAop开发过程中的坑

 

  学习交流群:

✅✅1:这是孙哥suns给大家的福利!

✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料

3:QQ群:583783824    工作微信:BigTreeJava 拉你进微信群,免费领取!

4:本文章内容出自上述:Spring应用课程!

5:以上内容,进群免费领取呦~

一:AOP开发中的坑

        编程人员在常规过程中不常遇到的问题,但是一旦遇到这个问题,就一定会出错

1:代码实例

public class TestASpectProxy {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext3.xml");
        UserService userService = (UserService) ctx.getBean("userService");
        userService.register(new User());
        //--------------aspect log-----------
        //--------------aspect tx-----------
        //UserServiceImpl.register
        //UserServiceImpl.login
    }
}
@Aspect
public class MyAspect {
    //这是一个类切入点,给所有的都加上额外功能
    @Pointcut("execution(* *..UserServiceImpl.*(..))")
    public void myPointcut(){}
    /**
     * ProceedingJoinPoint这个等效于MethodInvocation
     * 这里写的是额外功能的部分,现在的额外功能不需要实现接口了,只需要加入注解。
     * */
    @Around(value="myPointcut()")//在这里调用切入点表达式,就完成了整合。
    public Object arround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("--------------aspect log-----------");
        Object proceed = joinPoint.proceed();
        return proceed;
    }

    @Around(value="myPointcut()")
    public Object arround1(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("--------------aspect tx-----------");
        Object proceed = joinPoint.proceed();
        return proceed;
    }
}
public class UserServiceImpl implements UserService {
    @Override
    public void login(String username, String password) {
        System.out.println("UserServiceImpl.login");
    }

    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register");
        this.login("suns","123456");
    }
}


        测试结果并不符合预期,login方法调用的时候额外功能并没有展示,这个就是那个坑,为什么login方法没有执行额外功能呢?当我们的调用者调用register方法的时候,我们调用的是Proxy代理对象的Register方法,加入了日志加入了事务,最终执行了这两个额外功能,没有问题,但是调用login方法的时候,是在原有功能当中调用的login方法,调用的并不是代理对象中的login方法而是调用的login原生的login方法所以没有额外功能的加入。

        这个告诉我们的道理就是:方法中调用类中原始对象的方法的的时候,那么久不会有额外功能的引入,要想使调用方法的额外功能也展示需要调用代理对象的对应的方法,而不是原始对象的对应的方法。也就是说我们需要在我们的register方法中获取到Spring的工厂对象,进而拿到我们的代理对象,进而调用我们的代理对象的login方法,然而初步的想法是在register方法中创建Spring的工厂对象,然而这是不可取的,这是重量级资源,占用大量内存,可以采取的途径是让我们的UserServiceImpl 实现ApplicationContextAware接口,Aware的含义是知道的意思,这个接口中有一个方法是setApplicationContext,通过这个方法入参是工厂对象,Spring容器启动时会回调这个方法,将引用赋值给这个这个方法,所以我们实现方法之后,存一份就好了。

public class UserServiceImpl implements UserService, ApplicationContextAware {
    private ApplicationContext ctx;

    @Override
    public void login(String username, String password) {
        System.out.println("UserServiceImpl.login");
    }

    @Override
    public void register(User user) {
        System.out.println("UserServiceImpl.register");
        UserService userService = (UserService) ctx.getBean("userService");//userService是代理对象
        userService.login("suns","123456");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx = applicationContext;
    }
}


2:测试结果

public class TestASpectProxy {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext3.xml");
        UserService userService = (UserService) ctx.getBean("userService");
        userService.register(new User());
        //--------------aspect log-----------
        //--------------aspect tx-----------
        //UserServiceImpl.register
        //    --------------aspect log-----------
        //--------------aspect tx-----------
        //UserServiceImpl.login

    }
}
//实现了被调用的时候也有这个额外功能的实现。


        在同一个业务类中,进行业务方法间的相互调用的时候,只有最外层的方法,加入了额外功能了。

        内部的方法通过普通的方式进行调用,并没有额外功能,都是原始方法,那么如果想让内层的方法也调用代理对象的方法,就需要通过ApplicationContextAware获得工厂,进而获得代理对象

你可能感兴趣的:(#,Spring专栏,java,开发语言,Aop,Spring)