Spring框架(原理探索)分为两个部分:

  • Spring框架之IOC容器概述

  • 用配置文件和完全注解方式探索Spring中AOP

(一)Spring框架之IOC容器概述

IOC的底层原理

XML解析、工厂模式、反射

什么是IOC

  • 控制反转,把对象创建和对象之间的调用过程交给Spring进行管理

  • 使用IOC的目的:为了降低耦合度

  • 做入门案例就是IOC实现

IOC接口(BeanFactory)

IOC操作Bean管理(基于XML)

IOC操作Bean管理(基于注解)

开始步骤

1.新建Java项目,将Spring一下的jar包进行导入

commons-logging-1.2.jar

spring-context-5.3.20.jar

spring-beans-5.3.20.jar

spring-expression-5.3.20.jar

spring-core-5.3.20.jar

2.新建User对象

class User{
    public void Add(){
        System.out.println("add-------------");
    }
}

3.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置User对象的创建-->
    <bean id="user" class="com.company.User"></bean>
</beans>

4.进行测试代码编写

package com.company.TestDemo;
import com.company.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDemo {
    @Test
    public void Test(){
        // 加载配置文件
        ApplicationContext context=new ClassPathXmlApplicationContext("com/company/bean1.xml");
        //获取配置创建的对象
        User user = context.getBean("user", User.class);
        System.out.println(user);
        user.Add();
    }
}

IOC的过程(解决对象创建和对象之间调用的耦合度问题)

<bean id="user" class="com.company.User"></bean>
public class IOC{
    public static UserDao getDao(){
        String classValue= "com.company.User";//获取xml中包名
        Class clazz=Class.forName(classValue);//通过报名获取该类字节码
        return clazz.newInstance();//通过newInstance对该类进行实例化
    }
}

IOC接口

IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

Spring提供IOC容器实现两种方式:

1.BeanFactory: IOC容器基本的实现,是Spring内部的使用接口,不提供开发人员进行使用

加载配置获取的时候不会创建对象,在获取对象(getBean)或使用对象时候后才进行创建对象

2.ApplicationContext: BeanFactory接口的子接口,提供更对更强大的功能,一般有开发人员进行使用 加载配置文件的时候就进行对象创建

IOC操作Bean管理

什么是Bean管理

Spring创建对象

Spring注入属性

Bean管理操作有两种方式

(A)基于xml配置文件方式实现

在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象的创建

在bean标签里里面有很多属性,介绍常用的属性(id="唯一标识",class="包路径")

(1) 使用set方法进行属性赋值

<bean id="user" class="com.company.User">
        <property name="name" value="张三"></property>
        <property name="sex" value="20"></property>
    </bean>

或则使用p标签进行注入(添加:

xmlns:p="http://www.springframework.org/schema/p")

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user_p" class="com.company.User" p:name="李四" p:sex="23"></bean>
</beans>

(2) 使用有参构造方法注入

    <bean id="book" class="com.company.Book">
        <constructor-arg name="bname" value="高数"></constructor-arg>
        <constructor-arg name="price" value="70"></constructor-arg>
    </bean>

(3) 注入对象方式

    <bean id="UserDao" class="com.company.dao.UserDao"></bean>
    <bean id="UserServiceImpl" class="com.company.service.UserServiceImpl">
        <property name="userDaoInfo" ref="UserDao"></property>
    </bean>

(4) 注入数组/List/Map/Set & 外部Bean/内部Bean & 提取List(Util)方式

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    
    <util:list id="UtilList">
        <value>s</value>
        <value>m</value>
        <value>c</value>
        <value>w</value>
    </util:list>
    <bean id="UserDao" class="com.company.dao.UserDao">
        <property name="name" value="wei"></property>
        <property name="password" value="wei"></property>
    </bean>
    <bean id="UserDao1" class="com.company.dao.UserDao">
        <property name="name" value="min"></property>
        <property name="password" value="minpassword"></property>
    </bean>
    <bean id="UserServiceImpl" class="com.company.service.UserServiceImpl">
        <property name="userDaoInfo" ref="UserDao"></property>
        <property name="list1" ref="UtilList"></property>
        <property name="strings">
            <list>
                <value>chen</value>
                <value>qi</value>
                <value>wei</value>
            </list>
        </property>
        <property name="list">
            <list>
                <ref bean="UserDao"></ref>
                <ref bean="UserDao1"></ref>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="s" value="chen"></entry>
                <entry key="m" value="qiwei"></entry>
            </map>
        </property>
        <property name="sets">
            <set>
                <value>234</value>
                <value>456</value>
                <value>789</value>
            </set>
        </property>
    </bean>
</beans>

bean管理的特殊情况处理方法

设置默认null值

    <bean id="user" class="com.company.User">
        <property name="name" value="张三"></property>
        <property name="sex" value="20"></property>
        <property name="cite">
            <null/>
        </property>
    </bean>

设置特殊字符(设置默认属性值:<<北京>>)

方式一:设置为:value=“<<北京>>”

    <bean id="user" class="com.company.User">
        <property name="name" value="张三"></property>
        <property name="sex" value="20"></property>
        <property name="cite" value="&lt;&lt;北京>>"></property>
    </bean>

方式二:特殊内容写到CDATA中去

    <bean id="user" class="com.company.User">
        <property name="name" value="张三"></property>
        <property name="sex" value="20"></property>
        <property name="cite">
            <value>
                <![CDATA[<<北京>>]]>
            </value>
        </property>
    </bean>

IOC操作Bean管理

1.Spring有两种bean,一种普通bean,另外一种工厂bean(FactoryBean)

2.普通bean:在配置文件中定义bean类型就是返回类型

3.工厂bean:在配置文件定义bean类型可以和返回类型不一样(实现FactoryBean的getObject()方法就行)

如何设置单实例还是多实例

1.在bean标签中设置scopy属性设置:

(1) scopy="singleton",表示单实例对象(加载配置文件就创建对象)

(2) scopy="prototype",表示多实例对象(加载配置文件不创建对象,调用获取对象才创建对象)

IOC操作Bean管理(bean的生命周期)

1.生命周期

从对象创建到对象的销毁的过程

2.bean生命周期

(1) 通过构造器创建bean实例 (无参数构造)

(2) 为bean的属性设置属性值和对其他的bean引用(调用set方法)

(3) 把bean示例对象传递bean后置处理器的方法(postProcessBeforeInitialization)

(4) 调用bean的初始化的方法(需要进行配置初始化的方法)

(5) 把bean示例对象传递bean后置处理器的方法(postProcessAfterInitialization)

(6) bean可以使用了(对象获取到了)

(7) 当容器关闭时候,调用bean的销毁的方法(需要及进行配置销毁的方法)

3.代码示例

1.实体类的定义

package com.company;

public class Book {//实体类的定义
    private String bname;
    private String price;

    public void setBname(String bname) {
        System.out.println("第二步为bean对象设置属性值或引用外部bean");
        this.bname = bname;
    }

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

    public Book() {
        System.out.println("第一步通过无参构造方法创建bean对象");
    }

    public Book(String bname, String price) {
        this.bname = bname;
        this.price = price;
    }
    public void SeeBook(){
        System.out.println(bname+"::"+price);
    }
    public void initMethod(){
        System.out.println("第三步调用初始化方法");
    }
    public void destroyMethod(){
        System.out.println("第五步调用销毁方法!");
    }
}

相关xml定义

    <bean id="book" class="com.company.Book" init-method="initMethod" destroy-method="destroyMethod">
        <property name="bname" value="sun"></property>
        <property name="price" value="qwe"></property>
    </bean>

测试方法

public class TestDemo {
    @Test
    public void Test(){
        // 加载配置文件
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("com/company/bean1.xml");
        //获取配置创建的对象
        Book book=context.getBean("book",Book.class);
        System.out.println("第四步获取对象");
        book.SeeBook();
        context.close();//手动销毁

    }
}

运行结果

第一步通过无参构造方法创建bean对象
第二步为bean对象设置属性值或引用外部bean
在初始化之前执行的方法
第三步调用初始化方法
在初始化之后的执行方法
第四步获取对象
sun::qwe
第五步调用销毁方法!
IOC生命周期后置处理器
public class MyBean 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;
    }
}
    <!--    添加后置处理器-->
    <bean id="myBean" class="com.company.MyBean"></bean>

IOC的自动装配

什么是自动装配

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

bean标签属性autowire(byName/byType),配置自动装配。

<bean id="book" class="com.company.Book" init-method="initMethod" destroy-method="destroyMethod" autowire="byName">
 </bean>

(2) 外部文件实现自动装配

<?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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/util/spring-context.xsd">
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${cqw.driverClassName}"></property>
        <property name="url" value="${cqw.url}"></property>
        <property name="username" value="${cqw.userName}"></property>
        <property name="password" value="${cqw.password}"></property>
    </bean>
    <!--    引入外部文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
</beans>

IOC操作Bean管理(基于注解方式)

注解(@注解名),可以作用于类,方法及属性上添加,极其简化xml配置

Spring针对Bean管理中创建对象提供注解(以下都可以创建对象)

@Component

@Service

@Controller

@Repository

基于注解方式实现对象创建

1.引入依赖(spring-aop-5.3.20.jar)

2.开启组件扫描

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.company">
<!--        注解不包含扫描-->
<!--        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
<!--        注解包含扫描-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
</beans>

基于注解方式实现属性创建

@AutoWired : 根据属性类型进行自动装配

@Autowiredprivate MinDao minDao;
@Qualifier : 根据属性名称进行注入(调用接口指定其实现类名称)

@Autowired@Qualifier(value = "minDaoImpl1")private MinDao minDao;
@Resource : 可以根据类型注入,可以根据名称注入

@Resource(name = "minDaoImpl1")private MinDao minDao;
@Value :注入普通类型属性

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

(B)纯注解开发

定义config类并注解@Configuration @ComponentScan

package com.company.Config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"com.company"})
public class Config {
}
测试调用修改

public class TestDemo {
    @Test
    public void Test() throws SQLException {
        // 加载配置文件
        ApplicationContext context=new AnnotationConfigApplicationContext(Config.class);//参数为刚创建的类
        //获取配置创建的对象
        MinServiceImpl minService = context.getBean("minServiceImpl", MinServiceImpl.class);
        minService.Add();
    }
}