Spring 从入门到精通 (十七) AOP底层如何加工创建代理对象

关键词:Spring | AOP | 创建对象 | 底层

本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨

在这里插入图片描述

一、疑问?

为什么通过原始对象的 id 值从工厂拿实例,得到的却是代理对象?

二、一张图

在这里插入图片描述

三、编码

新建空maven项目,包目录结构如下:

在这里插入图片描述

依赖坐标 pom.xml

所需依赖如下:

<dependencies>
    <!--Spring Container Core-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.10.RELEASE</version>
    </dependency>
    <!--Spring AOP-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.1.10.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.8</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.3</version>
    </dependency>
    <!--Lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
    <!--单元测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>RELEASE</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

实体类 User

实体类使用了效率插件 Lombok

@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
    private String name;
    private String pwd1;
}

UserService 接口

业务层接口定义了简简单单两个方法

public interface UserService {
    void login(String name, String pwd1);
    void register(User user);
}

接口实现类 UserServiceImpl

实现业务层接口,此时的业务专心做自己的核心业务

public interface UserService {
    void login(String name, String pwd1);
    void register(User user);
}

工厂配置业务层 bean

在工厂中配置,业务层的 bean,交由容器管理

<bean id="userService" class="com.liu.service.UserServiceImpl"/>

ProxyBeanPostProcessor 核心

实现 BeanPostProcessor 在 bean 对象返回前进行一次再加工,怎么加工自己写,这里就使用之前学习的JDK动态代理,因为业务类实现了接口,创建响应的动态代理类对象

注意: 参数中的 Object bean 就是原始对象,在使用JDK创建代理类对象的时候,因为没有自己的类加载器,所以第一个参数随便借一个类加载器,第二个参数原始对象实现的接口,这样代理类对象才知道该区实现哪个接口,我们通过 Object bean 就可以获得,第三个参数写自己的附加操作,同时执行目标方法。

public class ProxyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("工厂加工了,拿到返回了代理对象");
                Object invoke = method.invoke(bean, args);
                return invoke;
            }
        };
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),
                bean.getClass().getInterfaces(),
                handler);
        return userServiceProxy;
    }
}

工厂配置

<bean id="proxyBeanPostProcessor" class="com.liu.factory.ProxyBeanPostProcessor"/>

Test 测试

编写测试类,去工厂中通过id userService 拿对象时,因为对象在返回时,被加工了,加工过程就是通过原始对象使用JDK动态代理技术创建出了动态代理类对象,并作为返回值返回,这也就是为什么通过 userService 拿到的是代理对象,而不是原始对象

@Test
public void t1(){
    ApplicationContext con = new ClassPathXmlApplicationContext("/spring.xml");
    UserService userService = (UserService) con.getBean("userService");
    userService.login("asd", "asda");
    userService.register(new User());
}

结果:

工厂加工了,拿到返回了代理对象
处理核心业务用户登录,并调用DAO~~~~
工厂加工了,拿到返回了代理对象
处理核心业务用户注册,并调用DAO~~~~

四、写在最后

座右铭:不要在乎别人如何看你,要在乎你自己如何看未来,看梦想,看世界…!

一起学习的可以私信博主或添加博主微信哦。

专栏:订阅专栏 ✅
关注:关注博主 🆙

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王子周棋洛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值