2022-12-9 学习理解IOC、DI、AOP

学习内容:

1. IOC 参考链接
IOC(inversion of control)控制反转、反转控制,是一种描述JAVA开发领域对象的创建及管理问题的思想。如,有类A依赖于类B,传统的开发方式中,往往是在类A中手动通过new关键字来new一个B的对象出来;而使用IOC思想的开发方式,不通过new来创建对象,而是通过IOC容器(spring框架)来帮助我们实例化对象,我们需要哪个对象直接从IOC容器里面取过去即可。

控制:指的是对象创建(实例化、管理)的权力
反转:控制权交给外部环境(Spring矿建、IOC容器)

IOC解决了什么问题?

  • 对象之间的耦合度或者说依赖程度降低
  • 资源变的容易管理,比如用spring容器提供的话很容易就实现一个单例

例如:在没有IOC思想的情况下,Service层想要使用DAO层的具体实现的话,因为不能直接new接口类,需要在ServiceImpl中手动new出UserDAO的具体实现类UserDAOImpl。
在这里插入图片描述

但若有新的需求,需要针对UserDAO接口开发出另一个具体实现类NewUserDAOImpl,所以需要修改ServiceImpl中new的对象,如果只有一个类引用了UserDAO的具体实现还好,但若许许多多地方都引用了UserDAO的具体实现的话,会需要修改许多地方。
在这里插入图片描述

使用IOC的思想,将对象的控制权(创建、管理)交由IOC容器去管理,在使用的时候直接向IOC容器要就可以了
在这里插入图片描述
2. DI 参考链接
IOC和DI的区别:
IOC是一种设计思想,这个思想是将原本在程序中手动创建对象的控制权交由spring框架来管理,并非spring特有的,IOC容器是spring用来实现IOC的载体,IOC容器实际上是个map(key,value),map中存放的是各种对象
DI:是IOC最常见以及最合理的实现方式,叫做依赖注入

(1)构造器方法注入
创建一个address类

public class Address {
    private String address;

    public Address() {
    }

    public Address(String address) {
        this.address = address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

配置bean.xml

	<bean id="address" class="com.kuang.pojo.Address">
        <constructor-arg index="0" value="diqui"/>
    </bean>

即,构造器注入是在bean标签内部使用constructor-arg标签
type属性:使用类型执行构造方法中参数的类型
index属性:使用构造方法的索引值来进行注入
name属性:使用构造方法中的参数名来注入
value属性:要注入的值(包括基本数据类型和string类型)
ref属性:要注入的值(引用在IOC容器中其他的bean对象)

优点:创建时必须执行构造方法中的全部参数bean才能被创建,保证了对象创建出来的变脸一定都有值
缺点:必须要指定全部参数,否则无法创建,使用该方式改变了对象的创建过程
(2)set注入(必须要有一个无参的构造方法,因为Spring调用一个对象的set方法注入前,这个对象必须先被实例化。所以在"使用set方法注入"的情况下Spring会首先调用对象的构造函数。
创建一个User类,给User一个Name属性
配置xml文件

<!--IOC创建对象的方式,默认使用无参的构造方法!-->
<bean id="user" class="com.kuang.pojo.User">
    <property name="name" value="张三"/>
</bean>

UserDaoImpl:

public class UserDaoImpl implements UserDao {

    @Override
    public void getUser() {
        System.out.println("默认获取用户的数据!");
    }
}


UserServiceImpl:

public class UserServiceImpl implements UserService {


    private UserDao userDao;


    //利用set进行动态实现值的注入!
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        userDao.getUser();
    }
}


本质上包含两步:
第一步,需要new UserServiceImpl()创建对象,所以需要默认构造函数
第二步,调用setUserDao()函数注入userDao的值,所以需要setUserDao()函数

依赖:bean对象的创建依赖于容器
注入:bean对象中的所有属性由容器来注入

为什么需要依赖:
应用程序需要IOC容器来提供对象需要的外部资源
谁注入谁:
IOC容器注入应用程序某个对象,应用程序依赖的对象
注入了什么:
注入某个对象需要的外部资源,包括对象、资源、常量数据
构造器注入和set注入之间的区别:参考链接
set注入流程:
set注入
构造器注入流程:
构造器注入

  • 对于Setter注入:因为Spring调用一个对象的set方法注入前,这个对象必须先被实例化。所以在"使用set方法注入"的情况下Spring会首先调用对象的构造函数。
  • 对于构造器注入:如果发现配置了对象的构造注入,那么Spring会在调用构造函数前把构造函数需要的依赖对象都实例化好,然后再把这些实例化后的对象作为参数去调用构造函数。

主要区别为:

  • 在使用构造函数和set方法依赖注入时,Spring处理对象和对象依赖的对象的顺序时不一样的
  • 通过构造函数的注入方式其实表达了2个对象间的一种强的依赖关系:组合关系
  • 通过set方法注入的方式表达了2个对象间较弱的依赖关系:聚合关系

(3)基于注解的注入(接口注入)
对于DI使用注解,将不再需要在Spring配置文件中声明Bean实例。Spring中使用注解,需要在原有Spring运行环境基础上再做一些改变,完成以下三个步骤。

  • 导入AOP的Jar包。因为注解的后台实现用到了AOP编程

  • 需要更换配置文件头,即添加相应的约束

  • 需要在Spring配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
    在这里插入图片描述

  • 定义Bean @Component ,该注解的value属性用于指定该bean的id值
    另外,Spring还提供了3个功能基本和@Component等效的注解:
     @Repository 用于对DAO实现类进行注解
     @Service 用于对Service实现类进行注解
     @Controller 用于对Controller实现类进行注解
    之所以创建这三个功能与@Component等效的注解,是为了以后对其进行功能上的扩展,使它们不再等效。

  • Bean的作用域@Scope 需要在类上使用注解@Scope,其value属性用于指定作用域。默认为singleton。

  • 基本类型属性注入@Value 需要在属性上使用注解@Value,该注解的value属性用于指定要注入的值。使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。

  • 按类型注入域属性@Autowired,@Autowired是spring的注解,需要在域属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式。使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。

  • 按名称注入域属性@Autowired与@Qualifier,需要在域属性上联合使用注解@Autowired与@Qualifier。@Qualifier的value属性用于指定要匹配的Bean的id值。同样类中无需setter,也可加到setter上。

  • 按名称注入域属性@Autowired与@Qualifier,需要在域属性上联合使用注解@Autowired与@Qualifier。@Qualifier的value属性用于指定要匹配的Bean的id值。同样类中无需setter,也可加到setter上。

  • @Autowired还有一个属性required,默认值为true,表示当匹配失败后,会终止程序运行。若将其值设置为false,则匹配失败,将被忽略,未匹配的属性值为null。

  • 域属性注解@Resource,也就是说@Resource是java自带的注解,@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。使用该注解,要求JDK必须是6及以上版本。
    (1)按类型注入域属性 @Resource注解若不带任何参数,则会按照类型进行Bean的匹配注入。
    (2)按名称注入域属性 @Resource注解指定其name属性,则name的值即为按照名称进行匹配的Bean的id。

  • Bean的生命始末@PostConstruct与@PreDestroy 在方法上使用@PostConstruct,与原来的init-method等效。在方法上使用@PreDestroy,与destroy-method等效。

  • 使用JavaConfig进行配置(替代的是applicationContext.xml)JavaConfig,是在Spring 3.0开始从一个独立的项目并入到Spring中的。JavaConfig可以看成一个用于完成Bean装配的配置文件,只不过是程序员使用Java自己编写的。
    在这里插入图片描述
    在这里插入图片描述

3. AOP
AOP: Aspect oriented programming,面向切面变成,是OOP(面向对象编程)的一种延续。OOP可以解决大部分的代码重复问题,但有些问题是处理不了的,比如在父类中的多个方法的相同位置出现了重复的代码,OOP就解决不了,这部分重复的代码,一般统称为横切逻辑代码。
在这里插入图片描述
AOP解决了什么问题:
AOP 主要用来解决:在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,将它们独立到非业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
相关术语:
(1)切面(Aspect): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
(2)连接点(Joint point): 表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。Joint point 是所有可能被织入 Advice 的候选的点, 在 Spring AOP中, 则可以认为所有方法执行点都是 Joint point,通俗的讲,连接点即表示类里面可以被增强的方法。
(3)通知(Advice): 定义了切面何时调用
(4)Before:在方法被调用之前调用通知
(5)After:在方法完成之后调用通知,无论方法执行是否成功
(6)After-returning:在方法成功执行之后调用通知
(7)After-throwing:在方法抛出异常后调用通知
(8)Around:通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
(9)切点(PointCut): 切点定义了何处,切点的定义会匹配通知所要织入的一个或多个连接点,我们通常使用明确的类的方法名称来指定这些切点,或是利用正则表达式定义匹配的类和方法名称来指定这些切点。PointCut 的作用就是提供一组规则来匹配 joinpoint, 给满足规则的 joinpoint 添加 Advice。
(10)目标对象(Target): 织入 Advice 的目标对象.。
(11)织入(Weaving): 将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

切入点表达式:
execution (public * com.ljb.service.impl….(…)),execution(权限修饰符,返回值类型,类全路径,方法名称,参数列表)
1.execution:指示符,execution是最常用的指示符,用于匹配方法执行的连接点。
2.public:访问修饰符,该参数可选。
3.第一个*号:返回值类型,号表示所有的类型,即通配符。
4.包名:需要拦截的包名,后面的两个点表示当前包和当前包的所有子包
5.第二个
号:类名,号表示所有的类。(…):方法名,*号表示所有方法,括号里面表示方法的参数,两个点表示任何参数,可有可无。

AOP实现原理:

  • 代理模式: 生成一个代理类代理另一个类的某个方法,大概可以这样:
class UserControllerProxy {
    private UserController userController;

    public void saveUser() {
        checkAuth();
        userController.saveUser();
    }
}

实际调用saveUser()时,调用的是代理对象的saveUser()方法。

静态代理和动态代理

AOP的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值