【Spring】最核心的两大组件 IOC/AOP 细讲之IOC

Spring框架核心细讲 IOC部分



前言

此次是对于自己所学Spring中的一些重要知识的回顾与知新, 从浅入深,从使用Spring的好处到核心底层


一、Spring框架概述

  1. Spring是轻量级的开源的JavaEE框架
  2. Spring可以解决企业级应用开发的复杂性
  3. Spring两个核心的部分:IOC / AOP
    (1) IOC:控制反转 将创建对象的过程交给Spring进行管理
    (2) AOP:面向切面,不修改源代码进行功能的加强
  4. Spring特点
    (1) 方便解耦 简化开发 – Spring将创建对象和注入属性全交给Spring管理
    (2) Aop编程支持 – 可以在不影响主程序的结构下,添加功能加强
    (3) 方便程序调试
    (4) 方便和其它框架进行整合 – Spring内部有很多对于其它框架的整合jar包
    (5) 方便进行事务操作
    (6) 降低API开发难度 – 一个配置 一个注解 干掉了以前几十行 上百行的工作量

二、IOC概念和原理

2.1 什么是IOC

(1) 控制反转,将对象创建和对象之间的调用过程,交给Spring进行管理
(2) 使用IOC目的,降低耦合度
(3) 做入门案例就是IOC实现

2.2 IOC底层原理

(1) xml解析 工厂模式 反射

将创建对象和注入属性的工作在配置文件写好 Spring只需要读取 操作就是
Spring有两种工厂模式创建对象的方式 后面会娓娓道来

反射:通过读取编译好的class文件,获取已经加载到内存中的类,来完成动态操作

2.3 Bean管理

2.3.1 基于xml方式创建对象

(1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
(2)在 bean 标签有很多属性,介绍常用的属性 * id 属性:唯一标识 * class 属性:类全路径(包类路径)
(3)创建对象时候,默认也是执行无参数构造方法完成对象创建

<!--
name:类里面属性的名称
value:向属性注入的值
-->
<!--配置User創建-->
<bean id="user" class="com.worker.spring5.User"></bean>

上面是最普遍的插入方法,接下来讲解静态工厂和实例工厂的方式

实体类
这里没什么特别需要讲的,无参有参构造器,getter,setter,toString即可

public class Book {
    private String name;
    private int price;
    private String detail;

    public Book() {
    }

    public Book(String name, int price, String detail) {
        this.name = name;
        this.price = price;
        this.detail = detail;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                ", detail='" + detail + '\'' +
                '}';
    }
}

静态工厂
创建一个staticFactory 静态工厂类
配置静态方法获取实体类Book 设置属性

//静态工厂
public class staticFactory {
    public static Book getBook(String bookName) {
        System.out.println("static静态工厂......");
        Book book = new Book();
        book.setName("javascript DOM编程艺术");
        book.setPrice(67.8);
        book.setDetail("学习使我强大");
        return book;
    }
}

实例工厂
创建一个 InstanceFactory 实例工厂类
配置实例方法获取实体类Book 设置属性

// 实例工厂
public class InstanceFactory {
    public Book getBook(String bookName) {
        System.out.println("实例工厂.......");
        Book book = new Book();
        book.setName("你不知道的javascript");
        book.setPrice(47.8);
        book.setDetail("学习使我强大");
        return book;
    }
}

xml配置文件
bean标签上使用 factory-method 指定创建对象的方法
factory-bean 指定工厂bean 实体使用
constructor-arg 该属性为有参构造器设置属性 工厂返回的是Book实例 前提是有对应几个参数的构造器

<!-- 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
    知识点:
    factory-bean指定使用那个工厂实例;
    factory-method指定使用那个工厂方法
    -->
    <!--1.static静态工厂-->
    <bean id="book1" class="com.worker618.factory.staticFactory" factory-method="getBook">
        <!--可以为方法指定参数-->
        <constructor-arg value="javascript"/>
    </bean>
    <!--2.实例工厂-->
    <bean id="InstanceFactory" class="com.worker618.factory.InstanceFactory"></bean>
    <bean id="book2" class="com.worker618.pojo.Book" factory-bean="InstanceFactory" factory-method="getBook">
        <constructor-arg value="javascipt"/>
    </bean>

</beans>

2.3.2 基于注解方式创建对象

1.什么是注解

(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:

  1、简化 xml 配置
  2、Spring 针对 Bean 管理中创建对象提供注解 
    (1)@Component  通用注解 当不知道该bean是什么层时使用
    (2)@Service Serviece服务层
    (3)@Controller  SpringMVC 控制层
    (4)@Repository  对应持久层即 Dao 层,主要用于数据库相关操作   
  • 上面四个注解功能是一样的,都可以用来创建 bean 实例
2.基于注解方式实现对象创建

1.引入依赖
在这里插入图片描述
2.开启组件扫描

  • 需要开启context命名空间
    如果扫描多个包,逗号隔开
    也可以将路径成到父包 对父类的扫描 完成了代码的冗余

3.注解里的value属性可以省略不写 默认是class类首字母小写形式

 <context:component-scan base-package="com.worker"></context:component-scan>

设置此属性为false 定制扫描规则

use-default-filters=“false” 默认为true 全部扫描 可以设置为false


<!--扫描文件包含有Controller注解的-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--扫描文件不包含有Controller注解的-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

4.基于注解方式实现属性注入

(1)@Autowired:根据属性类型进行自动装配
(2)@Qualifier:根据名称进行注入 这个@Qualifier 注解的使用,和上面@Autowired 一起使用
@Qualifier(value = “userDaoImpl1”) //根据名称进行注
(3)@Resource:可以根据类型注入,可以根据名称注入 —> javax.annotation.Resource
(4)@Value:注入普通类型属性

官方不推荐使用Resource

@Repository(value = "userDaoimpl2")
public class UserDaoimpl2 implements UserDao{
    @Override
    public void add() {
        System.out.println("add2......");
    }
}

/* 默认值类名称 首字母小写 */
@Service
public class UserService {
    // 不需要添加set方法
    @Autowired
    @Qualifier(value = "userDaoimpl1")
    private UserDao userDao1;

    @Resource(name="userDaoimpl2")
    private UserDao userDao2;

    @Value(value = "abc")
    private String name;
}

官方不推荐使用Resource

5.完全注解开发

创建配置类

//  将当前类作为配置类 替代xml配置文件
@ComponentScan(basePackages = {"com.worker"}) // 开启组件扫描
@Configuration // 该注解作用 使当前类作为Spring的配置类 替代xml配置文件
public class SpringConfig {
}

2.3.3 xml自动装配

1.什么是自动装配

(1)根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入

2.演示自动装配过程 autoWire属性完成

(1)根据属性名称自动注入
( 2 ) 根据 属性类型自动注入
注意点:同一个xml文件不可以出现多个相同类型的bean 并不清楚该选择哪个bean

 autowire="byName"
 autoWire="byType
 
<bean id="book" class="com.worker.spring5.bean.Book" init-method="init" destroy-method="destory" autowire="byName">
    <property name="bname" value="中国美食"></property>
</bean>

<!--配置后置处理器-->
<bean id="myBeanPost" class="com.worker.spring5.bean.MyBeanPost"></bean>

2.3.4 外部属性文件

1、直接配置数据库信息
<bean id="dataSourse" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="username" value="root"></property>
    <property name="password" value="1234"></property>
    <property name="url" value="jdbc:mysql//localhost:3307/test?useUnicode=true&setCharEncoding=utf-8"></property>
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>

读取配置文件进行注入属性
需要开启context命名空间

xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/context/spring-context.xsd">

<context:property-placeholder location="classpath:配置文件全名"/>

<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
    <!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
    <property name="driverClassName" value="${配置文件的name值}"></property>
    <property name="url" value="${配置文件的name值}"></property>
    <property name="username" value="${配置文件的name值}"></property>
    <property name="password" value="${配置文件的name值}"></property>

2.3.5 普通类型Bean:配置定义的bean类型就是返回类型

xml配置

<!--配置User創建-->
<bean id="user" class="com.worker.spring5.User"></bean>

Book类

private String bname;
//1.set方法注入
public void setBname(String bname) {
    this.bname = bname;
}

工厂Bean(FactoryBean):配置文件定义bean类型可以和返回类型不一样
需要继承FactoryBean<返回的类型>

//  Dept类
public class Dept implements FactoryBean<Course> {

    // 定义返回的类型
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setName("你是很帅的");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

xml配置

<bean id="dept" class="com.worker.spring5.bean.Dept"></bean>

2.3.6 Bean作用域

(1)Bean作用域分为seesion/request/application/singleton/prototype

作用域描述
singleton在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。
prototype每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。
session同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。
request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。
application限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。

(2)singleton 和 prototype 区别
第一 singleton 单实例,prototype 多实例
第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用 getBean 方法时候创建多实例对象

默认情况 bean单实例对象 scope=“singleton”
所以这里打印的实例地址都是一样的 \color{HotPink}{所以这里打印的实例地址都是一样的} 所以这里打印的实例地址都是一样的


@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Book book1 = context.getBean("book", Book.class);
    Book book2 = context.getBean("book", Book.class);
    System.out.println(book1);
    System.out.println(book2);
}

在这里插入图片描述

加上scope="prototype" 接下来创建的bean都是多实例对象 打印地址就会发生变化 \color{HotPink}{打印地址就会发生变化} 打印地址就会发生变化

 <bean id="book" class="com.worker.spring5.bean.Book" scope="prototype"></bean>

2.3.7bean的生命周期

1、生命周期

(1)从对象创建到对象销毁的过程

2、bean 生命周期

(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(4)bean 可以使用了(对象获取到了)
(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

3.配置 在bean中配置两个方法 init和destory xml中配置init-method destory-method属性 值为bean中定义的方法名
Book.class
public class Book {
    private String bname;

    public Book(){
        System.out.println("第一步 调用无参构造");
    }
    public void setBname(String bname) {
        this.bname = bname;
        System.out.println("第二步 调用set注入属性");
    }

    public void init(){
        System.out.println("第三步 初始化准备");
    }
    
// 第四步获取实例 创建对象

    public void destory(){
        System.out.println("第五步 结束了 销毁吧");
    }
}

x m l 配置 \color{hotpink}{xml配置} xml配置

<bean id="book" class="com.worker.spring5.bean.Book" init-method="init" destroy-method="destory">
    <property name="bname" value="中国美食"></property>
</bean>

在bean生命周期里还有初始化之前和初始化之后(需要配置后置处理器)
后置处理器类配置 需要继承BeanPostProcessor接口 重写两个方法

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之前执行的方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后执行的方法");
        return bean;
    }
}

x m l 配置 \color{hotpink}{xml配置} xml配置

<!--配置后置处理器-->
<bean id="myBeanPost" class="com.worker.spring5.bean.MyBeanPost"></bean>

三、扩展部分

3.1 区分环境的Bean

bean标签属性 profile: test(测试) / dev(开发)

<beans profile="test">测试环境</beans>
<beans profile="dev">开发环境</beans>
// 指定使用开发/测试环境的bean
System.setProperty("spring.profiles.active","test")
// 虚拟机参数位置加载 命令行指定
-Dspring.profiles.active=test

3.2 导入外部配置文件

作用:导入外部配置文件 各个配置文件因为业务拆分模块 最后导入到主配置文件 可读性加强 实现解耦与模块复用
import标签的resource指定xml配置文件路径
classpath为当前类路径作为根路径

// 随着Spring启动一起加载
<import resource="classpath:bean2.xml"></import>

3.3 有别名的Bean

使用alias标签 name(为哪个bean起别名) alias(起的别名) 两个属性

// 给bean起别名 与bean标签的name一样 与bean有这映射关系
<alias name="dept" alias="course"></alias>

3.4 常用的三种getBean方法

在这里插入图片描述

3.5 配置Connection

    <bean id="dept" class="com.worker.spring5.bean.Dept"></bean>

    <bean class="java.lang.Class" factory-method="forName">
        <constructor-arg name="className" value="com.mysql.jdbc.Driver"></constructor-arg>
    </bean>

    <bean id="connection" class="java.sql.DriverManager" factory-method="getConnection" scope="prototype">
        <constructor-arg name="url" value="jdbc:mysql:///test"/>
        <constructor-arg name="user" value="root"/>
        <constructor-arg name="password" value="1234"/>
    </bean>
</beans>

总结

以上就是今天要讲的内容,本文仅仅简单介绍了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值