spring的ioc和aop是什么

Spirng 的 IOC 和 AOP 几乎是面试官必问的一个问题,但是很多只是会从 Spring 中拿取对象,关于 Spring 的核心两个部分却不能够完整地去介绍,本篇文章将用图文的结合方式,全方位去分析 IOC 和 AOP。

图片[1]-spring的ioc和aop是什么-不念博客

题目

Spring 的 IOC 和 AOP

推荐解析

IOC 是什么?

IoC(Inversion of Control) 控制反转,是一种常见的设计思想,主要就是将手动创建对象的控制权,交给 Spring 框架来管理。

为什么需要存在一个容器?

解耦,将对象之间的相互依赖的关系交给 IOC 容器管理,并让容器完成对象注入,开发者不需要知道一个 Service 依赖的其他类,只需要从容器中拿取即可。

Spring Bean

Bean:被 IOC 容器所管理的对象俗称 Bean。

Bean 可以通过 XML、注解、配置类进行定义。

一般采用注解,如下

  • @Component:通用注解
  • @Repository:持久层 DAO 层
  • @Service:服务层 Service
  • @Controller:Spring MVC 控制层

怎么注入 Bean?

通常采用注解

  • @AutoWired 按类型装配,结合 @Qualifier 可以按名称装配。
  • @Resource 按名称装配
  • @Inject 按类型进行装配

Bean 的作用域

  • Singleton:Spring 中的 Bean 默认都是单例的,是对单例设计模式的应用,有线程安全问题。
  • Prototype:每次获取都会创建一个新的 Bean 实例。没有线程安全问题。
  • Request:(仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 Bean(请求 Bean),该 Bean 仅在当前 HTTP request 内有效。
  • Session:(仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 Bean(会话 Bean),该 Bean 仅在当前 HTTP session 内有效。
  • Application:(仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 Bean 仅在当前应用启动时间内有效。
  • Websocket:(仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 Bean。

Bean 的生命周期

(1)通过构造器创建 Bean 实例(无参数构造)

(2)为 Bean 的属性设置值和对其他 Bean 引用(调用 set 方法)

(3)把 Bean 实例传递 Bean 后置处理器的方法postProcessBeforeInitialization

(4)调用 Bean 的初始化的方法(需要进行配置初始化的方法)

(5)把 Bean 实例传递 Bean 后置处理器的方法 postProcessAfterInitialization

(6)Bean 可以使用了(对象获取到了)

(7)当容器关闭时候,调用 Bean 的销毁的方法(需要进行配置销毁的方法)

AOP 是什么?

SpringAOP 的意思是面向切面,利用 AOP 可以对业务逻辑的各个部分进行隔离,减少业务逻辑各部分之间的耦合度,提高程序可重用性。

Spring AOP 是在 Aspecj 基础上。

AOP 术语

连接点:可以被增强的方法

切入点:真正增强的方法

通知:真正增强的代码逻辑

切面:将通知应用到切入点的过程

AOP 的应用场景

1)自定义日志一般用 @Around

2)性能统计

3)事务管理 @Transactional 代理模式,增强方法。

4)权限管理,日常用的登录判断管理员和用户,自定义注解 + AOP 即可实现。

实现 AOP 的两种方式

1)JDK 动态代理(有接口的情况)

2)CGLIB 动态代理(没有接口的情况)

SpringBoot 1 和 Spring 5 默认用 JDK 动态代理

SpringBoot 2 开始默认使用 CGLIB 动态代理,原因是没有接口依然不会报错,性能略高于 JDK 动态代理。

JDK 动态代理示例代码

public class JDKProxy {
    public static void main(String[] args) {
        //创建接口实现类的代理对象
        UserDaoImpl userDao = new UserDaoImpl();
        Class[] interfaces = {UserDao.class};
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
        int result = dao.add(1, 2);
        System.out.println("result = " + result);
    }
}

class UserDaoProxy implements InvocationHandler {
    //1.把创建的是谁的代理对象,把谁传递过来
    //有参数构造器
    private Object obj;

    public UserDaoProxy(Object obj) {
        this.obj = obj;
    }

    //增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法之前:
        System.out.println("方法之前执行...." + method.getName() + ":传递的参数..." + Arrays.toString(args));


        //被增强的方法执行
        Object res = method.invoke(obj, args);
        //方法之后
        System.out.println("方法之后执行..." + obj);
        return res;
    }
}

AspectJ 定义的通知类型和返回顺序

  • 前置通知
  • 后置通知
  • 返回通知
  • 异常通知
  • 环绕通知

Spring 4 和 5 返回顺序的区别,Spring 5 将最终通知真正放到了最后。

Spring4版本
(1).正常情况
1.环绕之前通知
2.前置通知Before
3.被增强的方法
4.环绕之后通知
5.After最终通知
6.AfterReturning 后置通知
(2).异常情况
1.环绕之前通知
2.前置通知Before
3.被增强的方法
4.After最终通知
5.AfterThrowing 异常通知
Spring5版本
(1).正常情况
1.环绕之前通知
2.前置通知Before
3.被增强的方法
4.环绕之后通知
5.AfterReturning后置通知
6.After最终通知
(2).异常情况
1.环绕之前通知
2.前置通知Before
3.被增强的方法
4.AfterThrowing异常通知
5.After最终通知
© 版权声明
THE END