Java框架--Spring(轻量级容器框架)(入门+ioc)

2023-11-09

目录

一.概念

海绵hong对于ioc的理解:

二.spring快速入门

1.最基本的spring实例

1.1javabean类

1.2beans.xml

 1.3 ioc容器使用

2.spring 容器结构/机制

 2.1beanDefinitionMap

2.2singletonObject

2.3beanDefinitionNames

2.4注意点

三.Spring 管理 Bean-IOC

1.Spring配置/管理bean介绍

1.2bean的基于xml文件配置方式

1.3通过ref来配置bean

1.4引用/注入内部bean对象(同ref使用场景类似)

1.5引用/注入集合/数组类型 

1.6级联属性赋值

1.7通过静态工厂获取对象 

1.8通过实例工厂获取对象

1.9通过FactoryBean获取对象(重点)

1.10bean 配置信息重用(继承)

1.11 bean创建顺序

1.12bean对象的单例和多例

1.13bean的生命周期

1.14配置 bean 的后置处理器(进行统一管理)

1.16基于XML的bean的自动装配

1.17spring el表达式

2.基于注解配置bean

2.1基本介绍

2.2快速入门

2.3手动开发简单的spring基于注解配置的程序

2.4自动装配

2.5泛型依赖注入


spring学习的核心内容

IOC:控制反转,可以管理Java工具

AOP : 切面编程

JDBCTemplate : 是 spring 提供一套访问数据库的技术, 应用性强,相对好理解

声明式事务: 基于 ioc/aop 实现事务管理,

IOC, AOP 是重点同时难点

一.概念

1.spring可以整合其他的框架(是管理框架的框架)

2.spring有两个核心技术:IOC和AOP

3.IOC [Inversion Of Control 反转控制]

传统的开发模式[Jdbcutils/反射]

程序--->环境    //程序读取配置环境,然后自己创建对象

图片解析(以数据库为例说明):

1、程序员编写程序, 在程序中读取配置信息

2. 创建对象, new Object???() // 反射方式

3. 使用对象完成任务

IOC 的开发模式 [EmpAction EmpService EmpDao Emp]

程序<-----容器 //容器创建好对象,程序直接使用.

图片解析

1、Spring 根据配置文件 xml/注解, 创建对象, 并放入到容器(ConcurrentHashMap)中,

并且可以完成对象之间的依赖

2、当需要使用某个对象实例的时候, 就直接从容器中获取即可

3、程序员可以更加关注如何使用对象完成相应的业务, (以前是 new ... ==> 注解/配置

方式)

4. DI—Dependency Injection 依赖注入,可以理解成是 IOC 的另外叫法.

5. Spring 最大的价值,通过配置,给程序提供需要使用的

web 层[Servlet(Action/Controller)]/Service/Dao/[JavaBean/entity]对象,

这个是核心价值所在,也是 ioc 的具体体现, 实现解耦

海绵hong对于ioc的理解:

        本来属于你控制的事情,交由别人来控制,而你只在需要的时候进行获取就可以,把创建对象的过程交给Spring来进行管理,从而做到将原来需要自己手动new对象,变成直接从Spring中获取。

为何我们要使用ioc哪?

        我们来想想当我们需要点菜的时候可以直接去new一个对象,但是如果我们需要多次点这个菜,不可能一个菜只有一个人去购买把。难道我们还需要继续去new这个类吗?这样只会增加代码冗余,但是当我们使用ioc之后,就会发现不论是一个人还是多个人点这个菜都会从ioc中获取,而且当菜的属性发生变化只需要修改ioc中的即可

二.spring快速入门

1.最基本的spring实例

1.1javabean

package com.hong.spring;



/**

 * Created with IntelliJ IDEA.

 *

 * @Author: 海绵hong

 * @Date: 2022/09/28/10:51

 * @Description: JavaBean对象

 */

public class Car {

    private String id;

    private String name;

    private Double price;



    public Car() { //在反射调用的时候会使用car的无参构造器

    }



    public Car(String id, String name, Double price) {

        this.id = id;

        this.name = name;

        this.price = price;

    }





    public String getId() {

        return id;

    }



    public void setId(String id) {

        this.id = id;

    }



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }



    public double getPrice() {

        return price;

    }



    public void setPrice(double price) {

        this.price = price;

    }



    @Override

    public String toString() {

        return "Car{" +

                "id='" + id + '\'' +

                ", name='" + name + '\'' +

                ", price=" + price +

                '}';

    }

}

1.2beans.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"

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

<bean id="car01" class="com.hong.spring.Car">
        <property  value="001" name="id"/>
        <property value="兰博基尼" name="name"/>
        <property value="999999" name="price"/>

    </bean>

</beans>

​

 1.3 ioc容器使用

package com.hong.spring;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 海绵hong
 * @Date: 2022/09/28/10:55
 * @Description: 最基本的spring练习
 */
public class CarAppication {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("beans.xml");
        Car car01 = ioc.getBean("car01", Car.class);
        System.out.println("car01="+car01);
        System.out.println(car01.getName());
    }

}

2.spring 容器结构/机制

 2.1beanDefinitionMap

  1. beanDefinitionMap类型是ConcurrrntHashMap集合
  2. 存放beans.xml中的bean节点配置的bean对象的信息

2.1.1  table

  1. 在beanDefinitionMap中有属性table
  2. table使数组类型是ConcurrrntHashMap$Node
  3. 因为是数组所以可以存放很多的备案对象信息,就是beans.xml配置
  4. 初始化是512,当超过时,会自动扩容

例如上例:

  1. 通过hash算法我们的Car01对象的信息就保存在index=373位置
  2. 保存是以ConcurrrntHashMap$Node类型保存
  3. key就是beans.xml中配置的car01
  4. value就是car01对象的信息[属性/属性值/类信息/是不是懒加载]

2.2singletonObject

  1. 类型是ConcurrrntHashMap集合
  2. 存放初始化的对象(car01的属性名/属性值)

2.2.1table

  • 如果你在bean.xml文件中配置的对象是单例的就会初始化放在table中
  • 类型使ConcurrrntHashMap$Node

2.3beanDefinitionNames

  • 记录了我们在beans.xml中配置的bean的名称,方便查找

2.4注意点

如果在beans.xm中没有分配id系统会默认分配 id ,分配 id 的规则是 全类名#0 , 全类名#1 这样的规则来分配 id , 我们可以通过 debug 方式来查看。

三.Spring 管理 Bean-IOC

1.Spring配置/管理bean介绍

1.2bean的基于xml文件配置方式

1.2.1通过类型来获取bean

ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("beans.xml");
        Car car01 = ioc.getBean( Car.class);
        System.out.println("car01="+car01);
  1. 按类型来获取 bean, 要求 ioc 容器中的同一个类的 bean 只能有一个, 否则会抛出异常 NoUniqueBeanDefinitionException       
  2. 这种方式的应用场景:比如 XxxAction/Servlet/Controller, XxxService 在一个线程 中只需要一个对象实例(单例)的情况
  3. 这里在说明一下: 在容器配置文件(比如 beans.xml)中给属性赋值, 底层是通过 setter 方法完成的, 这也是为什么我们需要提供 setter 方法的原因

1.2.1 通过构造器配置bean(全参构造器)

constructor-arg标签可以指定使用构造器的参数

index表示构造器的第几个参数,从0开始计算

除了可以通过index,还可以通过那么/type初始化

   <bean id="car01" class="com.hong.spring.Car">
        <constructor-arg value="001" index="0"/>
        <constructor-arg value="兰博基尼" index="1"/>
        <constructor-arg value="999999" index="2"/>

    </bean>
 
    <bean id="car01" class="com.hong.spring.Car">
        <constructor-arg value="001" type="java.lang.String"/>
        <constructor-arg value="兰博基尼" type="java.lang.String"/>
        <constructor-arg value="999999" type="java.lang.Double"/>

    </bean>
使用细节
1. 通过 index 属性来区分是第几个参数
2. 通过 type 属性来区分是什么类型 ( 按照顺序 )
1.2.2通过p名称空间配置bean
<bean id="car01" class="com.hong.spring.Car"
          p:id="002"
          p:name="宝马"
          p:price="66666"

    />

1.3通过ref来配置bean

spring ioc 容器 , 可以通过 ref 来实现 bean 对象的 相互引用
该元素用来将bean中指定属性的值设置为对容器中的另外一个bean的引用。
bean 对象的相互引用
1. 其它含义和前面一样
2. ref 表示 memberDAO 这个属性将引用/指向 id = memberDAOImpl 对象

比如某些场景下有多个数据源,项目连了多个数据库,就可以分开管理 

一个bean需要引用多个bean对象的时候就可以使用ref连接起来
不同的javabean对象也可以进行相互调用

1.4引用/注入内部bean对象(同ref使用场景类似)

<bean id="memberServiceImpl02" class="com.hong.spring.Hong">
   <property name="age" value="18">
        <bean class="com.hong.spring.Hong"/>
    </property>
</bean>

1.5引用/注入集合/数组类型 

实例演示

package com.hong.spring.bean;

import java.util.*;

/**
 * @海绵hong
 * @version 1.0
 * Master类
 */
public class Master {

    private String name;//主人名

    private List<Monster> monsterList;
    private Map<String, Monster> monsterMap;
    private Set<Monster> monsterSet;

    //数组
    private String[] monsterName;

    //Java基础
    //这个Properties 是 Hashtable的子类 , 是key-value的形式
    //这里Properties  key和value 都是String
    private Properties pros;

    public String getName() {
        return name;
    }

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

    public List<Monster> getMonsterList() {
        return monsterList;
    }

    public void setMonsterList(List<Monster> monsterList) {
        this.monsterList = monsterList;
    }

    public Map<String, Monster> getMonsterMap() {
        return monsterMap;
    }

    public void setMonsterMap(Map<String, Monster> monsterMap) {
        this.monsterMap = monsterMap;
    }

    public Set<Monster> getMonsterSet() {
        return monsterSet;
    }

    public void setMonsterSet(Set<Monster> monsterSet) {
        this.monsterSet = monsterSet;
    }

    public String[] getMonsterName() {
        return monsterName;
    }

    public void setMonsterName(String[] monsterName) {
        this.monsterName = monsterName;
    }

    public Properties getPros() {
        return pros;
    }

    public void setPros(Properties pros) {
        this.pros = pros;
    }

    @Override
    public String toString() {
        return "Master{" +
                "name='" + name + '\'' +
                ", monsterList=" + monsterList +
                ", monsterMap=" + monsterMap +
                ", monsterSet=" + monsterSet +
                ", monsterName=" + Arrays.toString(monsterName) +
                ", pros=" + pros +
                '}';
    }
}
    <bean id="master01" class="com.hong.spring.beans.Master">
        <property name="name" value="太上老君"/> 
        <!-- 给 bean 对象的 list 集合赋值 -->
        <property name="monsterList">
            <list>
                <ref bean="monster03"/>
                <ref bean="monster02"/>
            </list>
        </property> 
        <!-- 给 bean 对象的 map 集合赋值 -->
        <property name="monsterMap">
            <map>
                <entry>
                    <key>
                        <value>monsterKey01</value>
                    </key>
                    <ref bean="monster01"/>
                </entry>
                <entry>
                    <key>
                        <value>monsterKey02</value>
                    </key>
                    <ref bean="monster02"/>
                </entry>
            </map>
        </property> 
        <!-- 给 bean 对象的 properties 集合赋值 -->
        <property name="pros">
            <props>
                <prop key="k1">Java 工程师</prop>
                <prop key="k2">前端工程师</prop>
                <prop key="k3">大数据工程师</prop>
            </props>
        </property> 
        <!-- 给 bean 对象的数组属性注入值 -->
        <property name="monsterName">
            <array>
                <value>银角大王</value>
                <value>金角大王</value>
            </array>
        </property>
    <!-- 给 bean 对象的 set 属性注入值 -->
        <property name="monsterSet">
            <set>
                <ref bean="monster01"/>
                <bean class="com.hong.spring.beans.Monster">
                    <property name="monsterId" value="10"/>
                    <property name="name" value="玉兔精"/>
                    <property name="skill" value="钻地洞"/>
                </bean>
            </set>
        </property>
    </bean>
使用细节
1. 主要掌握 List/Map/Properties 三种集合的使用 .
2. Properties 集合的特点 韩顺平 Java 工程师
1) 这个 Properties Hashtable 的子类 , key-value 的形式
2) key string value 也是 string
1.5.1 通过 util 名称空间来创建 list 集合 , 可以当做创建 bean 对象的工具来使用
<?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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

    <!--  可以达到数据复用
     通过 util 名称空间来创建 list 集合,可以当做创建 bean 对象的工具来使用 -->
    <util:list id="myListBook">
        <value>三国演义</value>
        <value>西游记</value>
        <value>红楼梦</value>
        <value>水浒传</value>
    </util:list>
    <bean id="bookStore" class="com.hspedu.spring.beans.BookStore">
        <property name="bookList" ref="myListBook"/>
    </bean>


</beans>

1.6级联属性赋值

spring ioc 容器 , 可以直接给对象属性的属性赋值, 即级联属性赋值
    <!-- 级联属性赋值 -->
    <bean id="emp" class="com.hong.spring.beans.Emp">
        <property name="name" value="jack"/>
        <property name="Dept" ref="dept"/>
<!--  这里我希望dept的name属性指定值[级联属性赋值]      -->
        <property name="Dept.name" value="Java 开发部"/>
    </bean>
    <bean id="dept" class="com.hspedu.spring.beans.Dept"/>

1.7通过静态工厂获取对象 

复习:

        静态代码块;作用就是对类进行初始化,而且它随这类的加载而执行,并且只会执行一次

        普通代码块:每创建一次对象就会执行。进行初始化内容

public class MyStaticFactory {
    private static Map<String, Monster> monsterMap;

    static {
        monsterMap = new HashMap<String, Monster>();
        monsterMap.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));
        monsterMap.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }

    public static Monster getMonster(String key) {
        return monsterMap.get(key);
    }
}
2. 修改 beans.xml , 增加配置
  <!-- 通过静态工厂来获取 bean 对象 -->
<!--   1.通过静态工厂获取/配置bean
       2.class是静态工厂类的全路径========会用com.hong.spring.factory.MyStaticFactory这个类的getMonster该方法返回monster_01这个的值 
       3.factory-method表示是指定静态工厂类的哪个方法返回对象
       4.constructor-arg表示取出静态工厂的哪个对象
       -->
    <bean id="my_monster" class="com.hong.spring.factory.MyStaticFactory"
          factory-method="getMonster"> <!-- constructor-arg 标签提供 key -->
        <constructor-arg value="monster_01"/>

1.8通过实例工厂获取对象

public class MyInstanceFactory {
    private Map<String, Monster> monster_map; //非静态代码块
    {
        monster_map = new HashMap<String, Monster>();
        monster_map.put("monster_01", new Monster(100, "猴子精", "吃人"));
        monster_map.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }

    public Monster getMonster(String key) {
        return monster_map.get(key);
    }
}
<!--    1.因为实例工厂要进行对象的实例化,所以第一个是配置实例工厂对象-->
    <bean id="myInstanceFactory" class="com.hspedu.hong.factory.MyInstanceFactory"/>
    <bean id="my_monster2" factory-bean="myInstanceFactory" factory-method="getMonster">
        <constructor-arg value="monster_02"/>
    </bean>
<!--
    1.factory-bean指定使用哪个实例工厂对象返回bean
    2.factory-bean指定使用实例工厂对象的哪个方法
    3.指定获取到实例工厂中的哪个对象
-->

</beans>

1.9通过FactoryBean获取对象(重点)

 
public class MyFactoryBean implements FactoryBean<Monster> {
    private String keyVal;
    private Map<String, Monster> monster_map;

    {
        monster_map = new HashMap<String, Monster>();
        monster_map.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));
        monster_map.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }

    public void setKeyVal(String keyVal) {
        this.keyVal = keyVal;
    }

    @Override
    public Monster getObject() throws Exception { 
    // TODO Auto-generated method stub 
        return this.monster_map.get(keyVal);
    }

    @Override
    public Class getObjectType() { 
    // TODO Auto-generated method stub 
        return Monster.class;
    }

    @Override
    public boolean isSingleton() { 
    // TODO Auto-generated method stub 
        return true;
    }
}
   <!-- 解读
    1. 通过 FactoryBean 来获取 bean 对象
    2. name="keyVal" 就是 MyFactoryBean 定义的 setKeyVal 方法
    3. value="monster_01" ,就是给 keyVal 的值 -->
    <bean id="myFactoryBean" class="com.hong.spring.factory.MyFactoryBean">
        <property name="keyVal" value="monster_01"/>
    </bean>

1.10bean 配置信息重用(继承)

当我们需要一个bean对象和之前存在的bean对象属性相同,我们直接复制这样会造成数据冗余,所以我们可以使用Java基础中的继承来解决这个问题

 <bean id="monster10" class="com.hong.spring.beans.Monster">
        <property name="monsterId" value="10"/>
        <property name="name" value="蜈蚣精"/>
        <property name="skill" value="蜇人"/>
    </bean>
    <!-- parent="monster10" 就是继承使用了 monster10 的配置信息 -->
    <bean id="monster11" class="com.hong.spring.beans.Monster"
          parent="monster10"/> 
    <!-- 当我们把某个bean设置为 abstract="true" 这个bean只能被继承,而不能实例化了 -->
    <bean id="monster12" class="com.hong.spring.beans.Monster" abstract="true">
        <property name="monsterId" value="12"/>
        <property name="name" value="美女蛇"/>
        <property name="skill" value="吃人"/>
    </bean>
    <!-- parent="monster12" 就是继承使用了 monster12 的配置信息 -->
    <bean id="monster13" class="com.hong.spring.beans.Monster" parent="monster12"/

1.11 bean创建顺序

说明
1. spring ioc 容器 , 默认是按照配置的顺序创建 bean 对象
<bean id="student01" class="com.hspedu.bean.Student" />
<bean id="department01" class="com.hspedu.bean.Department" />
会先创建 student01 这个 bean 对象,然后创建 department01 这个 bean 对象
2. 如果这样配置
<bean id="student01" class="com.hspedu.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.hspedu.bean.Department" />
会先创建 department01 对象,再创建 student01 对象
depends-on是这个bean依赖于后面的bean,就会先去创建depends-on属性的bean对象
bean对象是先创建bean对象之后在进行引用

1.12bean对象的单例和多例

说明
        在 spring ioc 容器 , 在默认是按照单例创建的,即配置一个 bean 对象后, ioc 容器只会
创建一个 bean 实例。
        如果, 我们希望 ioc 容器配置的某个 bean 对象,是以多个实例形式创建的则可以通过配置
scope="prototype" 来指定
<!-- 解读
    1. 在 spring 的 ioc 容器, 在默认情况下是安装单例创建的,
        即配置一个 bean 对象后, ioc 容器只会创建一个 bean 实例。
     2. 如果,我们希望 ioc 容器配置的某个 bean 对象, 
        是以多个实例形式创建(返回一个新的对象)的则可以通过配置 scope="prototype" 来指定 -->
    <bean name="car" scope="prototype" class="com.hong.spring.beans.Car"/>
使用细节
1. 默认是单例 singleton, 在启动容器时 , 默认就会创建 , 并放入到 singletonObjects 集合
2. <bean scope="prototype" > 设置为多实例机制后 , bean 是在 getBean() 时才创
3. 如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 (从singletonObjects 集合中拿出来), 可 以 指 定 懒 加 载 lazy-init ="true" ( 注意默认是 false)
4. 通常情况下 , lazy-init 就使用默认值 false , 在开发看来 , 用空间换时间是值得的 , 除非
有特殊的要求 .
5. 如果 scope="prototype" 这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在
getBean 时候,才创建对象 .

1.13bean的生命周期

说明 : bean 对象创建是由 JVM 完成的,然后执行如下方法
1. 执行构造器
2. 执行 set 相关方法
3. 调用 bean 的初始化的方法(需要配置)
4. 使用 bean
5. 当容器关闭时候,调用 bean 的销毁方法(需要配置)
public class House {
    private String name;

    public House() {
        System.out.println("House() 构造器");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("House setName()...");
        this.name = name;
    }

    public void init() {//初始化方法(由程序员自己定义)
        System.out.println("House init()..");
    }

    public void destory() {//销毁方法(由程序员自己定义)
        System.out.println("House destory()..");
    }
}

  <!-- 配置 bean 的初始化方法和销毁方法 -->
    <bean id="house" class="com.hong.spring.beans.House" 
          init-method="init" 
          destroy-method="destory">
        <property name="name" value="北京豪宅"/>
    </bean>
   public void beanLife () {
            ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
            House house = ioc.getBean("house", House.class);
            System.out.println(house); 
            //关闭容器
           ((ConfigurableApplicationContext) ioc).close();
            //因为ConfigurableApplicationContext中有close方法,所以需要转型
        }
使用细节
1. 初始化 init 方法和 destory 方法 , 是程序员来指定
2. 销毁方法就是当关闭容器时,才会被调用 .

1.14配置 bean 的后置处理器(进行统一管理)

说明
1. spring ioc 容器 , 可以配置 bean 的后置处理器
2. 该处理器 / 对象会在 bean 初始化方法 调用前和初始化方法调用后被调用
3. 程序员可以在后置处理器中编写自己的代码

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author 海绵hong
 * @version 1.0
 * 这是一个后置处理器, 需要实现 BeanPostProcessor接口
 */
public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     * 什么时候被调用: 在Bean的init方法前被调用
     * @param bean 传入在IOC容器中创建/配置的Bean
     * @param beanName 传入在IOC容器中创建/配置Bean的id
     * @return Object 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回
     * @throws BeansException
     */

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization().. bean="
                + bean + " beanName=" + beanName);

        //初步体验案例: 如果类型是House的统一改成 上海豪宅
        //对多个对象进行处理/编程==>切面编程
        if(bean instanceof House) {
            ((House)bean).setName("上海豪宅~");
        }
        return null;
    }

    /**
     * 什么时候被调用: 在Bean的init方法后被调用
     * @param bean  传入的在IOC容器中创建/配置Bean
     * @param beanName 传入的在IOC容器中创建/配置Bean的id
     * @return 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回
     * @throws BeansException
     */

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization().. bean="
                + bean + " beanName=" + beanName);
        return bean;
    }
}
   <!--配置House对象-->
    <bean destroy-method="destroy" init-method="init" id="house" class="com.hong.spring.bean.House">
        <property value="大豪宅" name="name"/>
    </bean>
    <bean destroy-method="destroy" init-method="init" id="house02" class="com.hong.spring.bean.House">
        <property value="香港豪宅" name="name"/>
    </bean>
    <!--配置了一个Monster对象-->
    <!--配置后置处理器对象
     1. 当我们在beans02.xml 容器配置文件 配置了 MyBeanPostProcessor
     2. 这时后置处理器对象,就会作用在该容器创建的Bean对象 
     3. 已经是针对所有对象编程->切面编程AOP -->
    <bean id="myBeanPostProcessor" class="com.hong.spring.bean.MyBeanPostProcessor"/>
</beans>
其它说明
1 、怎么执行到这个方法 ?=> 使用 AOP( 反射 + 动态代理 +IO+ 容器 + 注解 )
2 、有什么用? => 可以对 IOC 容器中所有的对象进行统一处理 , 比如 日志处理 / 权限的校
/ 安全的验证 / 事务管理 .
- 初步体验案例 : 如果类型是 House 的统一改成 上海豪宅
3 、针对容器的所有对象吗 ? 是的 => 切面编程特点
4,属性文件有中文需要转成unicode编码(去网站进行转化)
1.15通过属性文件给文件bean注入值
1. src/ 创建 my.properties
name=\u9EC4\u888D\u602A
id=10
skill=\u72EE\u5B50\u543C
2. 修改 src\beans.xml , 继续完成配置
<!--
    1. 通过属性文件给 bean 注入值,
    2. 需要导入: xmlns:context 名字空间,并指定属性文件路径
    3.location="classpath:my.properties表示属性所在的位置
    4.提示需要带上classpath
    5.我们的属性值通过${属性名}
    6.属性名就是my.properties文件中的k=v中的k
    -->
    <context:property-placeholder location="classpath:my.properties"/>
    <bean id="monster100" class="com.hong.spring.beans.Monster">
        <property name="monsterId" value="${id}"/>
        <property name="name" value="${name}"/>
        <property name="skill" value="${skill}"/>
    </bean>

1.16基于XML的bean的自动装配

D:\idea_java_projects\spring5\src\com\hong\spring\dao\OrderDao.java
D:\idea_java_projects\spring5\src\com\hong\spring\service\OrderService.java
D:\idea_java_projects\spring5\src\com\hong\spring\action\OrderAction.java
 <!--配置OrderDao对象-->
    <bean id="orderDao" class="com.hong.spring.dao.OrderDao"/>
    <!--配置OrderService对象老师解读
     1. autowire="byType" 表示 在创建 orderService时通过类型的方式 给对象属性 自动完成赋值/引用
     2. 比如OrderService 对象有 private OrderDao orderDao
     3. 就会在容器中去找有没有 OrderDao类型对象 
     4. 如果有,就会自动的装配, 老师提示如果是按照 byType 方式来装配, 这个容器中,不能有两个的OrderDao类型对象 
     5. 如果你的对象没有属性, autowire就没有必要写
     6. 其它类推..
     7. 如果我们设置的是 autowire="byName" 表示通过名字完成自动装配
     8. 比如下面的 autowire="byName" class="com.hspedu.spring.service.OrderService"
            1) 先看 OrderService 属性 private OrderDao orderDao
            2) 再根据这个属性的setXxx()方法的 xxx 来找对象id
            3) public void setOrderDao() 就会找id=orderDao对象来进行自动装配
            4) 如果没有就装配失败 -->
    <bean id="orderService" class="com.hong.spring.service.OrderService" autowire="byName"/>
    <!--配置OrderAction-->
    <bean id="orderAction" class="com.hong.spring.web.OrderAction" autowire="byName"/>

1.17spring el表达式

1. Spring Expression Language Spring 表达式语言,简称 SpEL 。支持运行时查询并可以操
作对象。
2. EL 表达式一样, SpEL 根据 JavaBean 风格的 getXxx() setXxx() 方法定义的属性访问
对象
3. SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL 表达式。
4. 不是重点 ,如果看到有人这样使用,能看懂即可
<!-- spring el 表达式 -->
    <bean id="spELBean" class="com.hong.spring.beans.SpELBean">
        <!-- sp el 给字面量 -->
        <property name="name" value="#{'海绵hong'}"/>
         <!-- sp el 引用其它 bean -->
        <property name="monster" value="#{monster01}"/>
        <!-- sp el 引用其它 bean 的属性值 -->
        <property name="monsterName" value="#{monster02.name}"/>
        <!-- sp el 调用普通方法 赋值 -->
        <property name="crySound" value="#{spELBean.cry('喵喵的..')}"/>
        <!-- sp el 调用静态方法 赋值 -->
        <property name="bookName" value="#{T(com.hspedu.spring.beans.SpELBean).read(' 天龙八部')}"/>
        <!-- sp el 通过运算赋值 -->
        <property name="result" value="#{89*1.2}"/>
    </bean>

2.基于注解配置bean

2.1基本介绍

基于注解的方式配置 bean, 主要是项目开发中的组件,比如 Controller Service 、和 Dao.
组件注解的形式有
1. @Component 表示当前注解标识的是一个组件
2. @Controller 表示当前注解标识的是一个控制器,通常用于 Servlet
3. @Service 表示当前注解标识的是一个处理业务逻辑的类,通常用于 Service 韩顺平 Java 工程师
4. @Repository 表示当前注解标识的是一个持久化层的类,通常用于 Dao

2.2快速入门

package com.hong.spring.component;
import org.springframework.stereotype.Repository;

/**
 * * @author 海绵hong
 * * @version 1.0
 */
@Repository
public class UserDao {
    
        }
        
        
package com.hspedu.spring.component;
 import org.springframework.stereotype.Service;

/*** @author 海绵hong
 *  * @version 1.0
 *  */
@Service
public class UserService {
    
  }
            
            
            
package com.hong.spring.component;
import org.springframework.stereotype.Controller;

/*** @author
 *  海绵hong
 *  * @version 1.0 
 *  */
@Controller
public class UserAction {
    
}
package com.hong.spring.component;
import org.springframework.stereotype.Component;

/*** @author 海绵hong
 *  * @version 1.0 
 *  */
@Component
public class MyComponent {
    
}


}

配置beans.xml

<!-- 配置自动扫描的包,注意需要加入 context 名称空间
    base-package:指定扫描的包 -->
 <context:component-scan base-package="com.hspedu.spring.component" />

含义是:当spring容器创建/初始化时,就会扫描这个包下的所以的有注解@Controller / @Service / @Respository / @Component 的类,将其类实例化,生成对象,放入到ioc容器

       public void getBeanByAnnotation () {
            ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
            UserAction userAction = ioc.getBean(UserAction.class);
            System.out.println(userAction);
            UserDao userDao = ioc.getBean(UserDao.class);
            System.out.println(userDao);
            MyComponent myComponent = ioc.getBean(MyComponent.class);
            System.out.println(myComponent);
            UserService userService = ioc.getBean(UserService.class);
            System.out.println(userService);
        }

注意事项和细节说明

1. <context:component-scan base-package="com.hspedu.spring.component" />
可以使用通配符 * 来指定 ,比如 com.hspedu.spring.* 表示
2.提问 : com.hspedu.spring.component 会不会去扫描它的子包 ?
答:会的
3. Spring IOC 容器不能检测一个使用了 @Controller 注解的类到底是不是一个真正的控
制器。注解的名称是用于程序员自己识别当前标识的是什么组件。其它的 @Service
@Repository 也是一样的道理 [ 也就是说 spring IOC 容器只要检查到注解就会生成对象,
但是这个注解的含义 spring 不会识别,注解是给程序员编程方便看的 ]
4.
<context:component-scanbase-package="com.hspedu.spring.component"
resource-pattern="User*.class" />

resource-pattern="User*.class": 表示只扫描满足要求的类(只扫描User打头的类)使用的少,不想扫描,不写注解就可以,

5. 需求:如果我们希望排除某个包/子包下的某种类型的注解,可以通过exclude-filter来指定
        1. context:exclude-filter 指定要排除哪些类
        2. type 指定排除方式 annotation表示按照注解来排除
        3. expression="org.springframework.stereotype.Service" 指定要排除的注解的全路径
 <context:component-scan base-package="com.hspedu.spring.component">
        <!-- 排除哪些类 , 以 annotaion 注解为例 -->
        <context:exclude-filter
                type="annotation"
                expression="org.springframework.stereotype.Service"/>
    </context>
6. 指定自动扫描哪些注解类
   <!-- 解读
    1. use-default-filters="false": 不再使用默认的过滤机制 
    2. context:include-filter: 表示只是扫描指定的注解的类 
    3. expression="org.springframework.stereotype.Controller": 注解的全类名 
    -->
    <context:component-scan base-package="com.hong.spring.component" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
7.默认情况:标记注解后, 类名首字母小写作为 id 的值 。也可以使用注解的 value 属性
指定 id 值,并且 value 可以省略。
@Controller(value="userAction01");
@Controller("userAction01");

2.3手动开发简单的spring基于注解配置的程序

2.3.1需求说明

1. 自 己 写 一 个 简 单 的 Spring 容 器 , 通 过 读 取 类 的 注 解 (@Component @Controller
@Service @Reponsitory) ,将对象注入到 IOC 容器
2. 也就是说,不使用 Spring 原生框架,我们自己使用 IO+Annotaion+ 反射 + 集合 技术实
, 打通 Spring 注解方式开发的 技术痛点
2.3.2思路分析

2.3.3代码实现

package com.hong.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 海绵hong
 * @Date: 2022/10/06/15:44
 * @Description:
 * 1.@Target(ElementType.TYPE)指定我们的HongComponentScan注解可以修饰type程序元素
 * 2.@Retention(RetentionPolicy.RUNTIME)指定HongComponentScan注解的保留范围
 * 3. String value() default ""; 表示ComponentScan 可以传入 value
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HongComponentScan {
    String value() default "";
}
package com.hong.spring.annotation;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 海绵hong
 * @Date: 2022/10/06/15:54
 * @Description:
 *这是一个配置类, 作用类似我们原生spring的 beans.xml 容器配置文件
 */
@HongComponentScan(value = "com.hong.spring.component")
public class HongSpringConfig {

}
package com.hong.spring.annotation;


import com.hspedu.spring.hspapplicationcontext.HspApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMa
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 海绵hong
 * @Date: 2022/10/06/20:53
 * @Description: HongSpringApplicationContext类的作用类似spring原生ioc容器
 */
public class HongSpringApplicationContext {
    private Class configClass;
    //ioc我存放的就是通过反射创建的对象(基于注解方式)
    private final ConcurrentHashMap<String, Object> ioc =
            new ConcurrentHashMap<>();

    //构造器
    public HongSpringApplicationContext(Class configClass) {

        this.configClass = configClass;
        //System.out.println("this.configClass=" + this.configClass);
        //获取要扫描的包
        //1. 先得到HongSpringConfig配置的的@ComponentScan(value = "com.hong.spring.component")
        ComponentScan componentScan =
                (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        //2. 通过componentScan的value=> 即要扫描的包
        String path = componentScan.value();
        System.out.println("要扫描的包= " + path);
        //得到要扫描的包下的所有资源(类 .class)
        //1.得到类的加载器
        ClassLoader classLoader =
                HongSpringConfig.class.getClassLoader();
        //2. 通过类的加载器获取到要扫描的包的资源 url=》类似一个路径
        path = path.replace(".", "/");//一定要把. 替换成 /
        URL resource =
                classLoader.getResource(path);
        System.out.println("resource=" + resource);
        //3. 将要加载的资源(.class) 路径下的文件进行遍历=>io
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                System.out.println("=====================");
                System.out.println("=" + f.getAbsolutePath());
                //D:\hong_spring\spring\out\production\spring\com\hong\spring\component\UserService.class
                //获取到 com.hpng.spring.component.UserService
                String fileAbsolutePath = f.getAbsolutePath();

                //这里我们只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {

                    //1. 获取到类名
                    String className =
                            fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
                    //System.out.println("className=" + className);
                    //2. 获取类的完整的路径(全类名)
                    //老师解读 path.replace("/",".") => com.hspedu.spring.component.
                    String classFullName = path.replace("/", ".") + "." + className;
                    //System.out.println("classFullName=" + classFullName);

                    //3. 判断该类是不是需要注入容器, 就看该类是不是有注解 @Component @Service..
                    try {
                        //这时,我们就得到老该类的Class对象
                        //Class clazz = Class.forName(classFullName)
                        //这里说一下
                        //1. Class clazz = Class.forName(classFullName) 可以反射加载类
                        //2. classLoader.loadClass(classFullName); 可以反射类的Class
                        //3. 区别是 : 上面方式后调用来类的静态方法, 下面方法不会
                        //4. aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> aClass = classLoader.loadClass(classFullName);
                        if (aClass.isAnnotationPresent(Component.class) ||
                                aClass.isAnnotationPresent(Controller.class) ||
                                aClass.isAnnotationPresent(Service.class) ||
                                aClass.isAnnotationPresent(Repository.class)) {

                            //这里老师演示一个Component注解指定value,分配id
                            //老师就是演示了一下机制.
                            if(aClass.isAnnotationPresent(Component.class)) {
                                //获取到该注解
                                Component component = aClass.getDeclaredAnnotation(Component.class);
                                String id = component.value();
                                if(!"".endsWith(id)) {
                                    className = id;//替换
                                }
                            }

                            //这时就可以反射对象,并放入到容器中
                            Class<?> clazz = Class.forName(classFullName);
                            Object instance = clazz.newInstance();
                            //放入到容器中, 将类名的首字母小写作为id
                            //StringUtils

                            ioc.put(StringUtils.uncapitalize(className) , instance);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    //编写方法返回对容器中对象
    public Object getBean(String name) {
        return ioc.get(name);
    }
}
package com.hong.spring.annotation;

import com.hong.spring.Hong;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 海绵hong
 * @Date: 2022/10/08/10:21
 * @Description:
 */
public class HongSpringApplicationContextTest {
        public static void main (String[]args){

            HongSpringApplicationContext ioc =
                    new HongSpringApplicationContext(HongSpringConfig.class);

            UserAction userAction = (UserAction) ioc.getBean("userAction");
            System.out.println("userAction" + userAction);

            MyComponent myComponent = (MyComponent) ioc.getBean("myComponent");
            System.out.println("myComponent" + myComponent);

            UserService userService = (UserService) ioc.getBean("userService");
            System.out.println("userService=" + userService);

            UserDao userDao = (UserDao) ioc.getBean("userDao");
            System.out.println("userDao=" + userDao);

            System.out.println("ok");
    }
}
注意事项和细节说明
        还可以通过@Component(value = "xx") @Controller(value = "yy") @Service(value = "zz") 中指定的 value, bean 分配 id

2.4自动装配

基本说明
1. 基于注解配置 bean ,也可实现自动装配(在xm中使用ref进行自动装配),使用的注解是: @AutoWired 或者 @Resource
2. @AutoWired 的规则说明
       spring会默认优先根据(被注解修饰的)属性类型去容器中找对应的组件(bean),找到就赋值;若找到多个相同类型的组件,再将属性的名称作为组件(bean)的id去容器中查找。
3. @Resource 的规则说明
        1) @Resource 有两个属性是比较重要的 , 分是 name type,Spring @Resource 注解的
name 属性解析为 bean 的名字 , type 属性则解析为 bean 的类型 . 所以如果使用 name
, 则使用 byName 的自动注入策略 , 而使用 type 属性时则使用 byType 自动注入策略
        2) 如果 @Resource 没有指定 name type , 则先使用 byName 注入策略 , 如果匹配不上 ,
再使用 byType 策略 , 如果都不成功,就会报错
4. 建议,不管是 @Autowired 还是 @Resource 都保证属性名是规范的写法就可以
注入
@Controller
public class UserAction {
    //xml配置 ref
    //说明 @Autowired
    //1)在IOC容器中查找待装配的组件的类型,如果有唯一的bean匹配(按照类型),则使用该bean装配
    //2)如待装配的类型对应的bean在IOC容器中有多个,则使用待装配的属性的属性名作为id值再进行查找,
    //  找到就装配,找不到就抛异常
    //@Autowired

    //说明 @Resource
    //1) @Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,
    //  而type属性则解析为bean的类型.所以如果使用name属性,则使用byName的自动注入策略,
    //  而使用type属性时则使用byType自动注入策略
    //  比如@Resource(name = "userService") 表示装配 id=userService对对象
    //  比如@Resource(type = UserService.class) 表示按照UserService.class类型进行装配, 这时要求容器中,只能有一个这样类型的对象
    //2) 如果@Resource 没有指定 name 和 type ,则先使用byName注入策略,
    //   如果匹配不上, 再使用byType策略, 如果都不成功,就会报错

    //=================================
    //说明: @Autowired + @Qualifier(value = "userService02") 组合也可以完成指定 name/id 来进行自动装配
    //指定id进行组装, 也可以使用@Autowired 和 @Qualifier(value = "userService02")
    // 这时,是装配的 id=userService02 , 需要两个注解都需要写上

    @Resource
    private UserService userService;

    public void sayOk() {
        System.out.println("UserAction 的sayOk()");
        System.out.println("userAction 装配的 userService属性=" + userService);
        userService.hi();
    }
}

2.5泛型依赖注入

基本说明
1. 为了更好的管理有继承和相互依赖的 bean 的自动装配,spring 还提供基于泛型依赖的 注入机制
2. 在继承关系复杂情况下,泛型依赖注入就会有很大的优越性

传统方法是将 PhoneDao /BookDao 自动装配到 BookService/PhoneSerive 中,当这
种继承关系多时,就比较麻烦,可以使用 spring 提供的泛型依赖注入

但是当我们

@Service 
public class PhoneService extends BaseService<Phone> { 
}

 PhoneService里面没有写

private PhoneDao Phonedao;

但是却注入里面就是基于泛型这套机制完成的

说明泛型基类的依赖关系,被子类自动继承,并根据泛型找到对应的子类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java框架--Spring(轻量级容器框架)(入门+ioc) 的相关文章

随机推荐

  • 子查询返回的值不止一个如何处理_从零学会SQL:复杂查询

    一 视图 视图作用 链接数据库与客户 查询时候表中存放的是临时数据 视图可以存放SQL查询语句 避免重复反复输入 降低工作量 SQL语句范例 create view 按性别汇总 性别 人数 as select 性别 count from s
  • 《区块链技术与应用》课堂笔记(五):比特币系统的实现原理

    区块链是一个去中心化的账本 比特币采用了 基于交易的账本模式 transaction based ledger 只记录了转账交易和铸币交易 并没有直接记录每个账户上有多少钱 如果想知道某个比特币账户上有多少钱 要通过交易记录来推算 UTXO
  • vivo 2020届校招在线编程笔试

    题目 运矿车 小v最近在玩一款挖矿的游戏 该游戏介绍如下 1 每次可以挖到多个矿石 每个矿石的重量都不一样 挖矿结束后需要通过一款平衡矿车运送下山 2 平衡矿车有左右2个车厢 中间只有1个车轮沿着导轨滑到山下 且矿车只有在2个车厢重量完全相
  • java实现输出1--100之间的质数

    输出1 100之间的质数 大于1 只能被1和本身整除的 再没有其他因数的数 迭代1 100 每个数都被小于它的数取余一遍 如果有一个为0 则跳出本次循环 都不为0则输出 public static void main String args
  • 学习笔记——Windows CMD设置为UTF-8编码

    Windows CMD设置为UTF 8编码 windows下的cmd的默认编码是GBK编码 有时可能造成乱码问题 下面是我找到的两种更换编码方式为UTF 8的方法 1 临时修改 1 先进入cmd命令窗口 快捷键win键 R 2 直接输入 c
  • LogStash 启动报错

    报错信息如下 exception gt LogStash ConfigLoadingError message gt The following config files contains non ascii characters but
  • Ubuntu搭建Nginx服务器

    Ubuntu搭建Nginx服务器 安装Nginx 配置文件 全局配置文件 子配置文件管理 sites availables和sites enabled default配置文件 启动 停止 重启Nginx 启动 停止 重启 查询 其他设置 自
  • macbookpro接口叫什么_【科普】什么是雷电接口?苹果电脑MACBOOK PRO有吗?

    刚接触笔记本的朋友不知道USB C口是什么 也不知道雷电接口 Thunderbolt 是什么 只知道MACBOOK PRO有雷电3接口 简单来说 雷电接口是USB TYPE C的替代模式 在此了解 什么是USB TYPE C 什么是雷电接口
  • 二叉树前中后层序遍历,迭代实现

    文章目录 前序遍历 代码 Python 代码 C 中序遍历 代码 Python 代码 C 后序遍历 代码 C 后序遍历 进阶写法 代码 Python 代码 C 层序遍历 代码 Python 代码 C 总结 上一篇文章介绍了二叉树的几种遍历方
  • 简历被pass,笔试被淘汰,还有什么办法能直通面试?

    互联网是目前的热门行业 越来越多的年轻人也是一心想要往上扑 1 互联网行业处于成长期 科技行业扶持力度大 未来整个行业的上升空间巨大 我们都知道 两个人同时出发 搭乘巨轮比乘坐小船更容易走的更快更远 互联网行业就是那搜巨轮 借力使力 越早上
  • C++数据结构X篇_09_C++实现队列的顺序存储与链式存储

    本篇参考C 实现队列的顺序存储与链式存储整理 先搞懂结构框架 后期根据视频利用c对内容实现 也可以对c有更高的提升 文章目录 1 顺序存储 2 链式存储 队列是一种特殊的数据存储结构 与栈不同的是其数据存储与访问顺序为先进先出 形式如下 下
  • linux 块设备 dm,[CentOS7]dm块设备删除

    报错 root node 3 dev lsblk lsblk dm 3 获取设备路径失败 lsblk dm 3 获取设备路径失败 查看映射信息并删除 root node 3 dev dmsetup ls ceph adb6548e 8602
  • 读取resource根目录下的配置文件---标准

    读取配置文件 fileName conf json public String getConf String fileName String content try jsonFile ResourceUtils getFile classp
  • 快速排序-递归与分治

    include
  • 服务器虚拟化和桌面虚拟化

    服务器虚拟化和桌面虚拟化依托的都是KVM架构 两者的底层的东西是一样的 只不过是人为的将这个底层系统二次开发成不同的系统版本 有些功能做了限制 有些做了优化 这样的好处是 不同的场景可以使用不同的虚拟化系统 更好的满足客户的需求和发挥不同系
  • 织梦搜索时因关键词标红而导致页面样式错乱的解决方法

    使用织梦默认的搜索功能时 发现搜索某一关键词时 搜索展示页面样式错乱了 经过排查 确定是关键词标红引起的 出现此问题的原因 织梦搜索页面会将搜索关键词进行标红 字体颜色改为红色 处理 在代码中体现出来就是将关键词文字替换为套上font标签的
  • 对华为路由器配置DHCP实现IP地址的自动分配

    目录 0 题目 1 首先按照题意建立如下拓扑图 并划分子网 2 为路由器AR1进行基础设置 1 将系统名称改为r1 2 设置超时时长为0 永不超时 3 为路由器AR1两个接口配置IP地址 1 GE 0 0 0 2 GE 0 0 1 3 检查
  • 处理不同的请求--设置content-type

    content type的作用 在http协议中 content type用来告诉对方本次传输的数据的类型是什么 在请求头中设置content type来告诉服务器 本次请求携带的数据是什么类型的 在响应头中设置content type来告
  • 写在28岁,回看3年前的自己,庆幸当时入了软件测试这行

    为什么会学习软件测试 已经28岁了 算一下快过去3年了 刚毕业那会工作了一年 因为自己当时很迷茫 觉得自己挺废的 所以就没去工作就一直在家 家里固定每个月给点生活费 但还是没钱 但家里给了我一套房子 出门300米左右就是地铁站 自己一个人住
  • Java框架--Spring(轻量级容器框架)(入门+ioc)

    目录 一 概念 海绵hong对于ioc的理解 二 spring快速入门 1 最基本的spring实例 1 1javabean类 1 2beans xml 1 3 ioc容器使用 2 spring 容器结构 机制 2 1beanDefinit