Spring IOC 和 Spring Aop 的入门和实战

 2023-01-13
原文作者:吃饭了呀呀呀 原文地址:https://juejin.cn/post/7137968321386774558

SpringIOC 和SpringAop的入门和实战

SpringIOC的解释

IOC(控制反转)就是依赖倒置原则的一种代码设计思路,就是把原先在代码里面需要实现的对象创建、对象之间的依赖、反转给容器来帮忙实现 SpringIOC 容器通过XML,注解等其他方式配置其他方式类以及类之间的依赖关系,完成了对象的创建和依赖的管理注入。实现IOC的主要设计模式是工厂模式。 这句话的意思是:

  • IOC控制反转的含义,它是把Java面向对象的创建的过程,交给容器来进行管理一种机制。
  • 它的实现方式,是通过XM,获取注解,配置类的方式实现类和类之间的依赖关系。
  • 来完成的对象的创建和依赖管理的注入。

SpringIOC的设计初衷是什么?

  • 集中管理,实现类的可配置和易管理
  • 减低类与类之间的耦合度,实现Java高内聚低耦合的设计思想
  • 同时可提升Java应用程序的性能,减轻JVM的内存压力

SpringIOC的核心概念

其实本质是通过:Java语言衍生出来的框架和项目产品,只不过开源出来。 使用spring最大的感受就是:很少使用new对象或者很少实例化对象 核心:创建对象,注入对象,控制对象等,一句话:springioc管理对象的整个生命周期。

总结: 面试题:谈谈你对SpringIOC的理解和认识是什么?

答:首先Spring框架是通过JAVA语言开发出来的一个框架或者一个项目产品。我们Java的最大的特点是:面向对象,在没有使用Spring框架的时候,我们要调用类中的方法或者给属性赋值,都是通过new去实例化对象,使用Spring框架以后,它内部提供IOC机制,也就是控制反转的含义,它的核心基础是:把对象创建的过程交由容器(Map)来进行管理一种机制,我们会把通过容器来管理对象的方式,将传统的创建更换成交由容器管理对象的过程称之为IOC控制反转的过程。总之如果要实现对象交由Spring的IOC来管理话,就必须遵循Spring提供的规范,而这些规范在传统spring开发中,是通过xml的方式来进行注入和管理的bean到容器中,现在主流的方式都是采用注解的方式进行的管理和控制bean到容器中,现在主流的方式都是采用注解的方式 来进行管理和控制bean到容器中等,这样做的好处是:

  • 集中管理,实现类的可配置和易管理。
  • 降低了类与类之间的耦合度。实现Java高内聚低耦合的设计思想。
  • 同时可以提升Java应用程序的性能,减轻JVM的内存压力。

DI:

它其实就是把容器中存在的类,如果这个类和另外一个类存在依赖关系的话,DI机制会把这个类中存在的类进行实例化 的过程称之为:依赖注入,但是前提是:必须要遵循依赖注入的规则:

1: set注入

2: 构建函数注入

3: 注解注入 @Resource/@Autowired

4: 工厂方法注入

SpringIOC容器的bean是单例的吗?

这个所谓的单列不是指:用所谓的单列模式开发和你们所认识的单列不一样。

在你们眼中的单列模式:恶汉模式,懒汉模式,双重检查机制等等。

它们的共同点是:在内存空间中只有一份内存,思想是一样的。

那么SpringIOC的bean的单例指是什么? 答案:就是一个容器Map,因为这个Map是一个全局的变量。

    public class Factory{
    	private final Map<String,BeanDefintion> beanDefinitionMap;
    
    	beanDefinitionMap.put("userServiceImpl",new); 
    }

所谓的依赖注入

所谓的依赖注入:其实就是告诉你,在实际的开发和生产中,类和类之间很多时候会存在所谓依赖关系。

为了这种一个对象依赖另外一个对象的时候,把存在依赖的对象实例化的过程中称之为:依赖注入。 DI:它其实就是把容器创建存放好的对象,通过DI机制去完成类执行对象的实例化的问题,说白了就是: 具体IOC动作。

IOC实战

导入Pom文件

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.15</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.4.RELEASE</version>
        </dependency>
    </dependencies>

基于XML和基于注解

基于XML:开发者把需要的对象在xml中配置,spring框架读取这个配置文件,根据配置文件的内容来创建对象

创建实体类

    @Data
    public class DataConfig {
        private String url;
        private String username;
        private String driverName;
        private String password;
    }

在resources目录下新建一个 spring.xml 配置类

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:c="http://www.springframework.org/schema/c"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
        <!-- 将bean注入到IOC容器中 -->
        <bean class="com.southwind.ioc.DataConfig" id="config">
            <!-- 为bean的某个属性赋值 -->
            <property name="username" value="root"></property>
        </bean>
    </beans>

测试

    public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
            System.out.println(context.getBean("config"));
        }

结果:

202301012007192461.png

基于注解

1、配置类

用一个Java类来替代xml文件,把在xml中配置的内容放到配置类中。

    @Configuration
    public class BeanConfiguration {
        @Bean(value = "config")
        public DataConfig dataConfig(){
            DataConfig dataConfig = new DataConfig();
            dataConfig.setDriverName("Driver");
            dataConfig.setPassword("root");
            dataConfig.setUrl("localhost:3306/dbname");
            dataConfig.setUsername("root");
            return dataConfig;
        }
    }

2、扫包+注解

    @Component
    public class DataConfig {
        private String url;
        private String username;
        private String driverName;
        private String password;
    }
    
       ApplicationContext context =new AnnotationConfigApplicationContext("com.southwind.ioc");
       System.out.println(context.getBean(DataConfig.class));

更简单的方式,不再需要依赖于xml或者配置类,而是将bean的创建交给目标类,在目标类中添加注解实现 ·@Autiwired 通过类型进行注入,如果需要通过名称取值 通过@Qualifier注解完成名称的映射

AOP

面向切面编程,是一种抽象化的面向对象编程,对面向对象编程的补充, 打印日志业务代码和打印日志耦合起来

计算器方法中,日志和业务混合在一起,aop要做的就是将日志代码全部抽象出去统一进行处理,计算器方法中只保留核心的业务代码。 做到核心业务和非业务代码的解耦合。

1. 创建切面类

2. 实现类添加@Component注解

3. 配置自动扫包,开启带自动生成代理对象

切面类:

    @Component
    @Aspect
    public class LoggerAspect {
    
        @Before(value = "execution(public int com.southwind.aop.CalImpl.*(..))")
        public void before(JoinPoint joinPoint) {
            String name = joinPoint.getSignature().getName();
            System.out.println(name + "方法的参数是:" + Arrays.toString(joinPoint.getArgs()));
        }
    
        @AfterReturning(value = "execution(public int com.southwind.aop.CalImpl.*(..))", returning = "result")
        public void afterReturning(JoinPoint joinPoint, Object result) {
            String name = joinPoint.getSignature().getName();
            System.out.println(name + "方法的结果是" + result);
    
        }
    }

目标类:

    public interface Cal {
        public int add(int num1,int num2);
        public int sub(int num1,int num2);
        public int mul(int num1,int num2);
        public int div(int num1,int num2);
    }
    @Component
    public class CalImpl implements Cal {
    
    
        public int add(int num1, int num2) {
            return num1 + num2;
        }
    
        public int sub(int num1, int num2) {
            return num1 - num2;
        }
    
        public int mul(int num1, int num2) {
            return num1 * num2;
        }
    
        public int div(int num1, int num2) {
            return num1 / num2;
        }
    }

在rosurces资源目录下开启动态代理

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:c="http://www.springframework.org/schema/c"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
        <!-- 自动扫包 -->
        <context:component-scan base-package="com.southwind.aop"></context:component-scan>
        <!-- 开启自动代理生成代理 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

测试:

    public class Test {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
            Cal bean = context.getBean(Cal.class);
            System.out.println(bean.add(1, 1));
            System.out.println(bean.sub(2, 1));
            System.out.println(bean.mul(1, 3));
            System.out.println(bean.div(4, 2));
        }
    }

结果:

202301012007207472.png