关于SpringAop创建的对象类型

14 篇文章 1 订阅
  • 测试一下没有任何Aop情况下的bean
  1. 定义 UserService
public interface UserService {

    void saveUser(String user);

}

2.定义一个UserService的实现,并加入IOC容器

@Service
public class UserServiceImpl implements UserService{
    @Override
    public void saveUser(String user) {
        System.out.println("保存用户:" + user);
    }
}

  1. 启动容器并尝试获取bean
    private ApplicationContext getContext(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.aop");
        return context;
    }

    @Test
    public void test1() throws Exception {
        ApplicationContext context = getContext();
        UserService bean = context.getBean(UserService.class);
        System.out.println(bean);//com.aop.service.UserServiceImpl@76c3e77a
    }

此时的bean就是一个普通的UserServiceImpl类实例

在这里插入图片描述

  • 尝试加入切面后获取
  1. 定义一个切面类
package com.aop.aspect;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {

    @Pointcut("within(com.aop.service.UserServiceImpl)")
    public void pointcut(){

    }

    @Before("pointcut()")
    public void before(){
        System.out.println("方法前置...");
    }

    @After(value = "pointcut()")
    public void after(){
        System.out.println("方法最终通知...");
    }

    @AfterThrowing(value = "pointcut()")
    public void afterThrow(){
        System.out.println("方法异常通知...");
    }

    @AfterReturning("pointcut()")
    public void afterReturn(){
        System.out.println("方法后置通知");
    }

}


2.尝试调用UserServiceImpl的方法

在这里插入图片描述
此时切面类生效了。我们再看一下UserServiceImpl的类型

在这里插入图片描述
在这里插入图片描述
很明显,此时的bean是一个代理对象,而且是Proxy和UserService类的实例,而不是UserServiceImpl的实例,因为此时Spring是用JDK动态代理去创建代理对象的,只能基于接口创建,相当于为UserService创建了一个实现类,而这个实现类中注入了被代理的对象,也就是UserServiceImpl。

那么既然这个bean也是Proxy的实例,那么我们从容器获取一个Proxy类也是可以的。
在这里插入图片描述

  • 去掉UserServiceImpl实现的接口
@Service
public class UserServiceImpl {
    public void saveUser(String user) {
        System.out.println("保存用户:" + user);
    }
}

此时该类没有实现任何接口,我们看看aop是否还能生效。

在这里插入图片描述
此时的切面还是生效了。我们看一下这个bean的类型

在这里插入图片描述
此时UserServiceImpl没有实现任何接口,Spring用了CGLIB生成了代理对象,那么此时的bean类型就是UserServiceImpl类型。

  • 新创建一个Service,看看能不能代理
@Service
public class OrderServiceImpl {

    public void saveOrder(){
        System.out.println("保存了订单...");
    }

}

在这里插入图片描述
发现此时OrderServiceImpl并没有被代理。原因是在写切入点表达式时只代理了UserServiceImpl。尝试修改一下切入点表达式

@Pointcut("execution(* com.aop.service..*(..))")

在这里插入图片描述
此时这两个bean都被代理了。

Spring在创建完bean以后会利用bean的后置处理器判断该bean是否
需要被代理(根据配置的切面的切入点表达式),如果需要,则用jdk获取cglib创建代理对象并注入被代理的对象,然后通过反射获取切面类中的各种增强方法,最终将这个代理对象重新放入容器中,在其他需要注入的地方使用。这就是使用容器带来的好处,只需要简单的配置,容器就可以生成代理对象并自动注入好。

  • 多个切面的配置
  1. 给容器中再注入一个切面类

在这里插入图片描述
2.尝试获取bean,并执行代码

在这里插入图片描述
此时发现,先切入了MyAspect,然年再切入了MyAspect1,这个是可以通过@Order注解来配置的,比如现在想先切入MyAspect1

@Component
@Aspect
@Order(value = 1)
public class MyAspect1 {
@Component
@Aspect
@Order(value = 2)
public class MyAspect {

在这里插入图片描述

此时就先切入了MyAspect1.切面的执行顺序类似SpringMVC的拦截器顺序。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值