spring基础知识(IOC、DI、AOP)

目录

一、spring概述

二、spring核心功能 ioc控制反转

1、什么是IOC

2、为什么要使用IOC

3、IOC的技术实现——DI依赖注入

     3.1Spring的第一个程序——spring创建对象的步骤

     3.2 DI依赖注入

   3.2.1基于XML的DI

   3.2.2基于注解的DI

   3.2.3注解与XML对比

四、面向切面编程AOP

4.1 概述

4.1.1动态代理的实现方式

4.1.2 动态代理的作用

4.1.3 AOP概述

4.1.4 AOP的实现

4.1.5 AOP的好处

4.2 AspectJ对AOP的实现

4.2.1 AspectJ切入点表达式

4.2.2 AspectJ 基于注解的 AOP 实现


一、spring概述

 Spring 的主要作用就是为代码“解耦”,降低代码间的耦合度。就是让对象和对象(模块和模块)之间关系不是使用代码关联,而是通过配置来说明。减轻对项目模块之间的管理, 类和类之间的管理, 帮助开发人员创建对象,管理对象之间的关系。
Spring 根据代码的功能特点,使用 Ioc 降低业务对象之间耦合度IoC 使得主业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由 Spring容器统一管理,自动“注入”,注入即赋值。 而 AOP 使得系统级服务得到了最大复用,且不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成“织入”

二、spring核心功能 ioc控制反转

1、什么是IOC

控制: 创建对象,对象的属性赋值,对象之间的关系管理。
反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,给属性赋值。

IOC:把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。

2、为什么要使用IOC

目的就是减少对代码的改动, 也能实现不同的功能。 实现解耦合。 

3、IOC的技术实现——DI依赖注入

Spring 容器是一个超级大工厂,负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean。Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”的方式来管理 Bean 之间的依赖关系。使用 IoC 实现对象之间的解耦和。spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制

3.1Spring的第一个程序——spring创建对象的步骤

1.创建maven项目


2.加入maven的依赖
  spring的依赖,版本5.2.5版本【spring-context】
  junit依赖【junit】


3.创建类(接口和它的实现类)
  和没有使用框架一样, 就是普通的类。

4.创建spring需要使用的配置文件
  在 src/main/resources/目录现创建一个 xml 文件,文件名可以随意,但 Spring 建议的名称为 applicationContext.xml。声明类的信息,这些类由spring创建和管理

实例化方式

(一)默认构造 <bean  id="" class=""/>:用于定义一个实例对象。一个实例对应一个 bean 元素。
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。
class:指定该 Bean 所属的类,注意这里只能是类,不能是接口

(二)静态工厂<bean id="" class="工厂类" factory-method="静态方法">

静态工厂:用于生成实例对象,所有的方法必须是static

public class MyBeanFactory {
	
	public static UserService createService(){
		return new UserServiceImpl();
	}
}
<!-- 将静态工厂创建的实例交予spring 
		class 确定静态工厂全限定类名
		factory-method 确定静态方法名
	-->
	<bean id="userServiceId" class="com.itheima.c_inject.b_static_factory.MyBeanFactory" factory-method="createService"></bean>

(三)实例工厂:<bean id="工厂id" class="工厂类">  <bean id="" factory-bean="工厂id" factory-method="方法">

必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是“非静态”的。

<!-- 创建工厂实例 -->
	<bean id="myBeanFactoryId" class="com.itheima.c_inject.c_factory.MyBeanFactory"></bean>
	<!-- 获得userservice 
		* factory-bean 确定工厂实例
		* factory-method 确定普通方法
	-->
	<bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createService"></bean>

 

5.测试spring创建的类

若 Spring 配置文件存放在项目的类路径下,则使用 ClassPathXmlApplicationContext 实现类进行加载。

测试方法规范:

     1)public 方法
     2)没有返回值 void 
     3)方法名称自定义,建议名称是test + 你要测试方法名称
     4)方法没有参数
     5)方法的上面加入 @Test ,这样的方法是可以单独执行的。 不用使用main方法。

3.2 DI依赖注入

di:依赖注入,表示创建对象,给属性赋值。

di的实现有两种:
1.在spring的配置文件中, 使用标签和属性完成,叫做基于XML的di实现
2.使用spring中的注解,完成属性赋值, 叫做基于注解的id实现

di的语法分类:
 1. set注入(设置注入): spring调用类的set方法,在set方法可以实现属性的赋值。
 2. 构造注入,spring调用类的有参数构造方法,创建对象。在构造方法中完成赋值。

3.2.1基于XML的DI

(1)set注入

set 注入也叫设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用

需要有set方法,没有set方法是报错的。并且调用的是默认的无参构造函数,如果重写了构造函数,一定要手动加入无参的构造函数才可

set注入(设值注入) :spring调用类的set方法, 你可以在set方法中完成属性赋值
         1)简单类型的set注入
            <bean id="xx" class="yyy">
               <property name="属性名字" value="此属性的值"/>
               一个property只能给一个属性赋值
               <property....>
            </bean>

         2) 引用类型的set注入 : spring调用类的set方法
           <bean id="xxx" class="yyy">
              <property name="属性名称" ref="bean的id(对象的名称)" />
           </bean>

(2)构造注入

构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器设置依赖关系。

构造注入:spring调用类有参数构造方法,在创建对象的同时,在构造方法中给属性赋值。构造注入使用 <constructor-arg> 标签
          <constructor-arg> 标签:一个<constructor-arg>表示构造方法一个参数
          <constructor-arg> 标签属性:
             name:表示构造方法的形参名
             index:表示构造方法的参数的位置,参数从左往右位置是 0 , 1 ,2的顺序
             value:构造方法的形参类型是简单类型的,使用value
             ref:构造方法的形参类型是引用类型的,使用ref

(3)引用类型的自动注入

对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为<bean/>标签,设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属
性)。根据自动注入判断标准的不同,可以分为两种:

  • byName:根据名称自动注入
  • byType: 根据类型自动注入

引用类型的自动注入: spring框架根据某些规则可以给引用类型赋值。·不用你在给引用类型赋值了
       使用的规则常用的是byName, byType.
       1.byName(按名称注入) : java类中引用类型的属性名和spring容器中(配置文件)<bean>的id名称一样,
                              且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
         语法:
         <bean id="xx" class="yyy" autowire="byName">
            简单类型属性赋值
         </bean>

       2.byType(按类型注入) : java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性
                              是同源关系的
,这样的bean能够赋值给引用类型
         同源就是一类的意思:
          1.java类中引用类型的数据类型和bean的class的值是一样的。
          2.java类中引用类型的数据类型和bean的class的值父子类关系的。
          3.java类中引用类型的数据类型和bean的class的值接口和实现类关系的
         语法:
         <bean id="xx" class="yyy" autowire="byType">
            简单类型属性赋值
         </bean>

注意:在byType中, 在xml配置文件中声明bean只能有一个符合条件的,多余一个是错误的

(4)集合类型注入

  <bean id="collDataId" class="com.itheima.f_xml.e_coll.CollData" >
		<property name="arrayData">
			<array>
				<value>DS</value>
				<value>DZD</value>
				<value>屌丝</value>
				<value>屌中屌</value>
			</array>
		</property>
		
		<property name="listData">
			<list>
				<value>于嵩楠</value>
				<value>曾卫</value>
				<value>杨煜</value>
				<value>曾小贤</value>
			</list>
		</property>
		
		<property name="setData">
			<set>
				<value>停封</value>
				<value>薄纸</value>
				<value>关系</value>
			</set>
		</property>
		
		<property name="mapData">
			<map>
				<entry key="jack" value="杰克"></entry>
				<entry>
					<key><value>rose</value></key>
					<value>肉丝</value>
				</entry>
			</map>
		</property>
		
		<property name="propsData">
			<props>
				<prop key="高富帅">嫐</prop>
				<prop key="白富美">嬲</prop>
				<prop key="男屌丝">挊</prop>
			</props>
		</property>
	</bean>

集合的注入都是给<property>添加子标签
              数组:<array>
                     List:<list>
                     Set:<set>
                     Map:<map> ,map存放k 键值对,使用<entry>描述
                     Properties:<props>  <prop key=""></prop>  
              普通数据:<value>
              引用数据:<ref>

(5)为应用指定多个spring配置文件

在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将
Spring 配置文件分解成多个配置文件。

包含关系的配置文件:多个配置文件中有一个总文件,总配置文件将各其它子文件通过<import/>引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可。

包含关系的配置文件:
         spring-total表示主配置文件 : 包含其他的配置文件的,主配置文件一般是不定义对象的。
         语法:<import resource="其他配置文件的路径" />
         关键字:"classpath:" 表示类路径(class文件所在的目录),
               在spring的配置文件中要指定其他文件的位置, 需要使用classpath,告诉spring到哪去加载读取文件。

       在包含关系的配置文件中,可以通配符(*:表示任意字符)
       注意: 主的配置文件名称不能包含在通配符的范围内

3.2.2基于注解的DI

(1) 定义 Bean 的注解@Component

@Component: 创建对象的, 等同于<bean>的功能
      属性:value 就是对象的名称,也就是bean的id值,
           value的值是唯一的,创建的对象在整个spring容器中就一个
     位置:在类的上面
 
   @Component(value = "myStudent")等同于
    <bean id="myStudent" class="com.bjpowernode.ba01.Student" />
 
   spring中和@Component功能一致,创建对象的注解还有:
   1.@Repository(用在持久层类的上面) : 放在dao的实现类上面,
                表示创建dao对象,dao对象是能访问数据库的。
   2.@Service(用在业务层类的上面):放在service的实现类上面,
              创建service对象,service对象是做业务处理,可以有事务等功能的。
   3.@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,
               控制器对象,能够接受用户提交的参数,显示请求的处理结果。
   以上三个注解的使用语法和@Component一样的。 都能创建对象,但是这三个注解还有额外的功能。
   @Repository,@Service,@Controller是给项目的对象分层的。

(2) 简单 类型属性注入@Value
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。

 @Value: 简单类型的属性赋值
        属性: value 是String类型的,表示简单类型的属性值
        位置: 1.在属性定义的上面,无需set方法,推荐使用。
                    2.在set方法的上面

(3)byType 自动注入@Autowired
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上。

 引用类型
      @Autowired: spring框架提供的注解,实现引用类型的赋值。
      spring中通过注解给引用类型赋值,使用的是自动注入原理 ,支持byName, byType
      @Autowired:默认使用的是byType自动注入
     
       位置:1)在属性定义的上面,无需set方法, 推荐使用
                  2)在set方法的上面

(4)byName 自动注入@Autowired 与@Qualifier

引用类型

如果要使用byName方式,需要做的是:
       1.在属性上面加入@Autowired
       2.在属性上面加入@Qualifier(value="bean的id") :表示使用指定名称的bean完成赋值。

属性:required ,是一个boolean类型的,默认true
           required=true:表示引用类型赋值失败,程序报错,并终止执行。
          required=false:引用类型如果赋值失败, 程序正常执行,引用类型是null

(5)JDK 注解@Resource 自动注入

 引用类型
      @Resource: 来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值
              使用的也是自动注入原理,支持byName, byType .默认是byName
       位置: 1.在属性定义的上面,无需set方法,推荐使用。
                   2.在set方法的上面
默认是byName: 先使用byName自动注入,如果byName赋值失败,再使用byType

小结:

注入  --> 字段或setter方法

              普通值:@Value

              引用值:

                     类型:@Autowired

                     名称1:@Autowired  @Qualifier("名称")

                     名称2:@Resource("名称")

3.2.3注解与XML对比

四、面向切面编程AOP

4.1 概述

4.1.1动态代理的实现方式

jdk动态代理使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
             jdk动态代理要求目标类必须实现接口

  cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类
             子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的

4.1.2 动态代理的作用

    1)在目标类源代码不改变的情况下,增加功能
    2)减少代码的重复
    3)专注业务逻辑代码
    4)解耦合,让你的业务功能和日志,事务非业务功能分离。

4.1.3 AOP概述

AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,可通过运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 Spring 框架中的一个重要内容。利用 AOP
可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

  Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。
          切面的特点: 一般都是非业务方法,独立使用的。
  Orient:面向, 对着。
  Programming:编程

  oop: 面向对象编程

  怎么理解面向切面编程 ? 
   1)需要在分析项目功能时,找出切面。
    2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
    3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能

  术语:
   1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。非业务功能,
              常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。

   2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法
    3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法
    4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象
    5)Advice:通知,通知表示切面功能执行的时间。

    说一个切面有三个关键的要素:
    1)切面的功能代码,切面干什么
    2)切面的执行位置,使用Pointcut表示切面执行的位置
    3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。

4.1.4 AOP的实现

 aop是一个规范,是动态的一个规范化,一个标准
    aop的技术实现框架:
    1.spring:spring在内部实现了aop规范,能做aop的工作。
              spring主要在事务处理时使用aop。
                 我们项目开发中很少使用spring的aop实现。 因为spring的aop比较笨重。


   2.aspectJ: 一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。
      aspectJ框架实现aop有两种方式:
       1.使用xml的配置文件 : 配置全局事务
        2.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。

4.1.5 AOP的好处

1.减少重复;
2.专注业务;
注意:面向切面编程只是面向对象编程的一种补充。

4.2 AspectJ对AOP的实现

4.2.1 AspectJ切入点表达式

4.2.2 AspectJ 基于注解的 AOP 实现

AspectJ 中常用的通知有五种类型:
1)前置通知
2)后置通知
3)环绕通知
4)异常通知
5)最终通知

(1)实现步骤

@Aspect : 是aspectj框架中的注解。
      作用:表示当前类是切面类
      切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
      位置:在类定义的上面

切面类中的方法定义规范
     定义方法,方法是实现切面功能的。
     方法的定义要求:
     1.公共方法 public
     2.方法没有返回值
     3.方法名称自定义
     4.方法可以有参数,也可以没有参数。
       如果有参数,参数不是自定义的,有几个参数类型可以使用。

@Before: 前置通知注解
        属性:value ,是切入点表达式,表示切面的功能执行的位置。
        位置:在方法的上面
      特点:
       1.在目标方法之前先执行的
       2.不会改变目标方法的执行结果
       3.不会影响目标方法的执行。

指定通知方法中的参数 : JoinPoint
      JoinPoint:业务方法,要加入切面功能的业务方法
         作用是:可以在通知方法中获取方法执行时的信息, 例如方法名称,方法的实参。
         如果你的切面功能中需要用到方法的信息,就加入JoinPoint.
        这个JoinPoint参数的值是由框架赋予, 必须是第一个位置的参数

后置通知定义方法,方法是实现切面功能的。
      方法的定义要求:
      1.公共方法 public
      2.方法没有返回值
      3.方法名称自定义
      4.方法有参数的,推荐是Object ,参数名自定义

@AfterReturning:后置通知
         属性:1.value 切入点表达式
              2.returning 自定义的变量,表示目标方法的返回值的。
               自定义变量名必须和通知方法的形参名一样。
         位置:在方法定义的上面
      特点:
       1. 在目标方法之后执行的。
       2. 能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
           Object res = doOther();
       3. 可以修改这个返回值
    
       后置通知的执行
         Object res = doOther();
         参数传递: 传值, 传引用
         myAfterReturing(res);
         System.out.println("res="+res)

环绕通知方法的定义格式
       1.public
       2.必须有一个返回值,推荐使用Object
       3.方法名称自定义
       4.方法有参数,固定的参数 ProceedingJoinPoint

@Around: 环绕通知
         属性:value 切入点表达式
         位置:在方法的定义什么
     特点:
        1.它是功能最强的通知
        2.在目标方法的前和后都能增强功能。
        3.控制目标方法是否被调用执行
        4.修改原来的目标方法的执行结果。 影响最后的调用结果
   
       环绕通知,等同于jdk动态代理的,InvocationHandler接口
     
       参数:  ProceedingJoinPoint 就等同于 Method
              作用:执行目标方法的
       返回值: 就是目标方法的执行结果,可以被修改。
       环绕通知: 经常做事务, 在目标方法之前开启事务,执行目标方法, 在目标方法之后提交事务

异常通知方法的定义格式
      1.public
       2.没有返回值
       3.方法名称自定义
       4.方法有个一个Exception, 如果还有是JoinPoint

  @AfterThrowing:异常通知
          属性:1. value 切入点表达式
               2. throwinng 自定义的变量,表示目标方法抛出的异常对象。
                  变量名必须和方法的参数名一样
      特点:
        1. 在目标方法抛出异常时执行的
       2. 可以做异常的监控程序, 监控目标方法执行时是不是有异常。
           如果有异常,可以发送邮件,短信进行通知
     
       执行就是:
        try{
            SomeServiceImpl.doSecond(..)
        }catch(Exception e){
            myAfterThrowing(e);
        }

 最终通知方法的定义格式
       1.public
       2.没有返回值
       3.方法名称自定义
       4.方法没有参数,  如果还有是JoinPoint

 @After :最终通知
         属性: value 切入点表达式
        位置: 在方法的上面
      特点:
       1.总是会执行
       2.在目标方法之后执行的
     
       try{
          SomeServiceImpl.doThird(..)
       }catch(Exception e){
     
       }finally{
           myAfter()
      }

@Pointcut: 定义和管理切入点, 如果你的项目中有多个切入点表达式是重复的,可以复用的
                 可以使用@Pointcut
         属性:value 切入点表达式
        位置:在自定义的方法上面
      特点:
        当使用@Pointcut定义在一个方法的上面 ,此时这个方法的名称就是切入点表达式的别名
        其它的通知中,value属性就可以使用这个方法名称,代替切入点表达式了

 

  • 7
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: SpringDI(依赖注入)和IOC(控制反转)是Spring框架中的两个核心概念。DI是指通过外部容器来注入对象的依赖关系,而不是在对象内部创建或查找依赖对象。IOC是指将对象的创建和依赖关系的管理交给容器来完成,而不是由对象自己来管理。\[1\] 在Spring中,IOC容器的初始化过程包括加载配置文件、解析配置文件、实例化Bean对象并将其存储在IOC容器中。可以通过注解来实现基于注解的容器初始化,通过在类上添加注解来标识其作为Bean,并通过注解来指定依赖关系。\[2\] AOP(面向切面编程)是Spring框架中的另一个重要概念,它允许在程序运行期间动态地将额外的行为织入到代码中,而不需要修改原始代码。AOP的实现方式包括基于代理的方式和基于字节码增强的方式。AOP的原理是通过在目标方法的前后插入切面逻辑来实现。\[2\] 在Spring中,可以通过注解来标识切面,并通过注解来指定切入点和通知类型。常用的AOP注解包括@Aspect、@Pointcut、@Before、@After等。\[3\] 总结来说,DIIOCSpring框架中用于管理对象依赖关系的机制,而AOP是用于实现横切关注点的机制。它们都是Spring框架中重要的特性,可以帮助开发者更好地组织和管理代码。 #### 引用[.reference_title] - *1* [Spring IoCAOP的通俗理解](https://blog.csdn.net/qq_39144436/article/details/123394242)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [关于SpringIoCAOP的面试题,快看看你都能答上来哪些](https://blog.csdn.net/Gaowumao/article/details/124919483)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [面试汇总-Spring-IOCAOP](https://blog.csdn.net/weixin_37672801/article/details/126415598)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值