用通俗易懂的语言谈谈我对IOC和AOP的理解

前言

  我们都知道Spring有两个重要的特性,那就是IOC和AOP,而这两个特性也是我们在求职过程中经常被问到的问题,下面我们就这两个特性结合实例来详细说明一下。

一、IOC

  IOC英文全称为“Inverse of Control”即控制反转的意思,它并不是一种技术,而是一种设计思想与理念。便是最初由我们在程序中自己手动new一个对象改变成交给Spring容器来控制并管理。简单的说,IOC你可以理解为一个Map集合,而Map存放的是各种对象,当我们需要用的时候就直接去获取这个key。

  IOC容器里面管理着各个对象之间的依赖关系并且完成对象的注入。这样做就会简化了我们在应用程序中的开发,从而将应用程序从复杂的依赖中解放出来,最终达到了程序解耦的目的。

  从上面的描述中我们知道IOC带来的改变不仅仅是在程序上的体现,它给我们带来的最大的改变是从思想上的改变,使得原本是主动的应用程序变成被动的了,被动的去等待IOC容器中生成对象并推给它想要的资源。通俗点说就是“你别过来找我,你等着就行,我会给你的”

用通俗易懂的语言谈谈我对IOC和AOP的理解

IOC初始化过程

下面我们通过代码来了解一下

<bean id="contentService" class="com.qxwo.service.impl.ContentServiceImpl"></bean>
<bean id="contentController" class="com.qxwo.service.ContentController" scope="prototype">
		<!-- 注入Service -->
		<property name="contentService" ref="contentService" />
</bean>
// 注入service
private ContentService contentService;
		
public void setContentService(ContentService contentService) {
		this.contentService = contentService;
}

我们从上面的代码中可以看出,spring通过<property>元素会自动调用contentService的set方法,像这样在我们的ContentController类中就自动的获得了contentService的对象,而不需要我们手动去创建这个对象。本文来源于公众号:【Java学习提升】 专注于Java领域技术分享,Java知识体系学习、分享面试经验,让我们结伴而行,共同成长!

二、AOP

  aop的英文全称为“Aspect Oriented Programming”,我们不难看出直观的意思为面向切面编程。它可以封装那些和业务没有关系的但是又给那些业务模块调用的逻辑封装起来,如我们常见的事务处理、系统日志和权限控制等应用场景。这样有利于减少系统的代码重复量,降低系统耦合度,对系统将来的可扩展性和可维护性有着很大的好处。

  AOP本身是基于动态代理的,假如要代理某个对象或者现实某个接口,这时AOP将使用JDK Proxy完成代理对象的创建。但是对于一些没有实现接口的对象,就不能使用JDK Proxy去代理对象的创建了,这种情况下该如何创建呢?这时它会使用Cglib生成一个被代理对象的子类作为代理,如下图所示:

用通俗易懂的语言谈谈我对IOC和AOP的理解

通过Cglib生成一个被代理对象的子类作为代理

下面我来用用户操作日志的场景来距离说明下:

首先maven中引入

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
import cn.hutool.json.JSONUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
@Order(1)//值越小,优先级越高
public class SaveUserLogDemo {

    private Logger log = LoggerFactory.getLogger(getClass());

    //申明一个切点
    @Pointcut("execution(public * com.qxwo.demo.*(..))")

    private void controllerAspect() {
    }

    //在方法执行前请求
    @Before(value = "controllerAspect()")
    public void methodBefore(JoinPoint joinPoint) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //打印请求接口的内容
        log.info("请求的接口地址:" + request.getRequestURL().toString());
        log.info("请求的方式:" + request.getMethod());
        log.info("请求的方法参数:" + Arrays.toString(joinPoint.getArgs()));

    }

    //在方法执行后请求
    @AfterReturning(returning = "o", pointcut = "controllerAspect()")
    public void methodAfterReturing(Object o) {
        log.info("Response内容:" + JSONUtil.toJsonPrettyStr(o));
    }
}

这样我们就可以收集用户请求接口的相关信息,包括接口的地址、请求方式、请求的参数以及执行时间等信息。

原创声明:本文为【Java学习提升】原创博文,转载请注明出处。

本文来源于公众号:【Java学习提升】 专注于Java领域技术分享,Java知识体系学习、分享面试经验,让我们结伴而行,共同成长!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章