Spring框架学习笔记(二):Spring IOC容器配置 Bean,分别基于XML配置bean 和 基于注解配置 bean

Spring 配置/管理 bean 介绍

Bean 管理包括两方面 :创建 bean 对象;给 bean 注入属性

Bean 配置方式:基于 xml 文件配置方式;基于注解方式

基于 XML 配置 bean

2.1 通过类型来获取 bean

方法:给getBean传入一个Class对象

示例:

ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster = ioc.getBean(Monster.class);

说明:

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

2.2 通过构造器配置 bean

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

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

(3)除了可以通过index 还可以通过 name / type 来指定参数方式,name表示参数的名字,type表示参数的类型

(4)类的构造器,不能有完全相同类型和顺序的构造器,所以可以通过type来指定

<bean id="monster03" class="com.spring.bean.Monster">
    <constructor-arg value="200" index="0"/>
    <constructor-arg value="白骨精" index="1"/>
    <constructor-arg value="吸人血" index="2"/>
</bean>

<bean id="monster04" class="com.spring.bean.Monster">
    <constructor-arg value="200" name="monsterId"/>
    <constructor-arg value="白骨精" name="name"/>
    <constructor-arg value="吸人血" name="skill"/>
</bean>


<bean id="monster05" class="com.spring.bean.Monster">
    <constructor-arg value="300" type="java.lang.Integer"/>
    <constructor-arg value="白骨精~" type="java.lang.String"/>
    <constructor-arg value="吸人血~" type="java.lang.String"/>
</bean>

说明:

  • 通过 index 属性来区分是第几个参数
  • 通过 type 属性来区分是什么类型(按照参数顺序)

2.3 通过 p 名称空间配置 bean

xml 文件配置, 增加命名空间配置

将光标放在p , 输入alt+enter , 就会自动的添加xmlns

示例:

<!--通过p名称空间来配置bean
    将光标放在p , 输入alt+enter , 就会自动的添加xmlns
-->
<bean id="monster06" class="com.spring.bean.Monster"
      p:monsterId="500"
      p:name="红孩儿"
      p:skill="吐火"
/>

2.4 引用/注入外部 bean 对象

在 spring 的 ioc 容器, 可以通过 ref 来实现 bean 对象的相互引用

应用案例:

(1) 创建 MemberDAOImpl.java
public class MemberDAOImpl {
    public MemberDAOImpl() {
        System.out.println("MemberDAOImpl 构造器...");
    }
    public void add() {
        System.out.println("MemberDAOImpl add()方法");
    }
}

(2)建 MemberServiceImpl.java

public class MemberServiceImpl {

    private MemberDAOImpl memberDAO;
    public MemberServiceImpl() {
        System.out.println("MemberServiceImpl 构造器~");
    }
    public void add() {
        System.out.println("MemberServiceImpl add()...");
        memberDAO.add();
    }
    public void setMemberDAO(MemberDAOImpl memberDAO) {
        this.memberDAO = memberDAO;
    }
    public MemberDAOImpl getMemberDAO() {
        return memberDAO;
    }
}

(3)beans.xml 配置

<!-- bean 对象的相互引用
1. 其它含义和前面一样
2. ref 表示 memberDAO 这个属性将引用/指向 id = memberDAOImpl 对象
-->
<bean id="memberServiceImpl" class="com.spring.service.MemberServiceImpl">
    <property name="memberDAO" ref="memberDAOImpl"/>
</bean>
<bean id="memberDAOImpl" class="com.spring.dao.MemberDAOImpl"/>

(5)测试

ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");
MemberServiceImpl bean = (MemberServiceImpl)ioc.getBean("memberServiceImpl", MemberServiceImpl.class);
System.out.println(bean);

细节说明:

  • 这里就体现出spring容器的依赖注入
  • 注意在spring容器中, xml是作为一个整体来执行的, 即如果你引用到一个bean对象, 对你配置的顺序没有要求,即bean的顺序没有要求
  • 建议还是按顺序,好处是阅读的时候,比较方便

2.5 引用/注入内部 bean 对象

spring ioc 容器中, 可以直接在 bean 内部配置内部 依赖 bean 对象

示例:
<!--配置MemberServiceImpl对象-使用内部bean-->
<bean class="com.spring.service.MemberServiceImpl" id="memberService2">
    <!--自己配置一个内部bean-->
    <property name="memberDAO">
        <bean class="com.spring.dao.MemberDAOImpl"/>
    </property>
</bean>

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

spring ioc 容器, bean 对象的集合/数组类型属性赋值

应用案例:

(1)创建 Master.java

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Master {

    private String name;
    private List<Monster> monsterList;
    private Map<String, Monster> monsterMap;
    private Set<Monster> monsterSet;
    private String[] monsterName;
    //这个 Properties 是 Hashtable 的子类 , 是 key-value 的形式
//这里 Properties key 和 value 都是 String
    private Properties pros;
    public Master() {
    }
    public Master(String name) {
        this.name = name;
    }
    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 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 Properties getPros() {
        return pros;
    }
    public void setPros(Properties pros) {
        this.pros = pros;
    }
}

(2)配置 beans.xml

<!--配置Master对象
体会 spring 容器配置特点 依赖注入-非常灵活
-->
<bean class="com.spring.bean.Master" id="master">
    <property name="name" value="太上老君"/>
    <!--给list属性赋值-->
    <property name="monsterList">
        <list>
            <!--引用的方法-->
            <ref bean="monster01"/>
            <ref bean="monster02"/>
            <!--内部bean-->
            <bean class="com.spring.bean.Monster">
                <property name="name" value="老鼠精"/>
                <property name="monsterId" value="100"/>
                <property name="skill" value="吃粮食"/>
            </bean>
        </list>
    </property>
    <!--给map属性赋值-->
    <property name="monsterMap">
        <map>
            <entry>
                <key>
                    <value>monster03</value>
                </key>
                <!--这里使用的外部bean,引入-->
                <ref bean="monster03"/>
            </entry>
            <entry>
                <key>
                    <value>monster04</value>
                </key>
                <ref bean="monster04"/>
            </entry>
        </map>
    </property>
    <!--给set属性赋值-->
    <property name="monsterSet">
        <set>
            <ref bean="monster05"/>
            <ref bean="monster06"/>
            <bean class="com.spring.bean.Monster">
                <property name="name" value="金角大王"/>
                <property name="skill" value="吐水"/>
                <property name="monsterId" value="666"/>
            </bean>
        </set>
    </property>
    <!--给数组属性赋值
        array标签中使用 value 还是 bean , ref .. 要根据你的业务决定
    -->
    <property name="monsterName">
        <array>
            <value>小妖怪</value>
            <value>大妖怪</value>
            <value>老妖怪</value>
        </array>
    </property>
    <!--给Properties属性赋值 结构k(String)-v(String)-->
    <property name="pros">
        <props>
            <prop key="username">root</prop>
            <prop key="password">123456</prop>
            <prop key="ip">127.0.0.1</prop>
        </props>
    </property>
</bean>

(3)测试

public static void main(String[] args) {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Master master01 = ioc.getBean("master", Master.class);
    //获取 list 集合
    System.out.println("======list=======");
    List<Monster> monster_list = master01.getMonsterList();
    for (Monster monster : monster_list) {
        System.out.println(monster);
    }
    //获取 map 集合
    System.out.println("======map=======");
    Map<String, Monster> monster_map = master01.getMonsterMap();
    Set<Map.Entry<String, Monster>> entrySet = monster_map.entrySet();
    for (Map.Entry<String, Monster> entry : entrySet) {
        System.out.println(entry);
    }
    //获取 properties 集合
    System.out.println("======properties=======");
    Properties pros = master01.getPros();
    String property1 = pros.getProperty("username");
    String property2 = pros.getProperty("password");

    String property3 = pros.getProperty("ip");
    System.out.println(property1 + "\t" + property2 + "\t" + property3);
    //获取数组
    System.out.println("======数组=======");
    String[] monsterName = master01.getMonsterName();
    for (String s : monsterName) {
        System.out.println("妖怪名= " + s);
    }
    //获取 set
    System.out.println("======set=======");
    Set<Monster> monsterSet = master01.getMonsterSet();
    for (Monster monster : monsterSet) {
        System.out.println(monster);
    }
}

运行效果:

细节说明:

(1)主要掌握 List/Map/Properties 三种集合的使用 .
(2)Properties 集合的特点
  • 这个 Properties Hashtable 的子类 , key-value 的形式
  • key string value 也是 string

2.7 通过 util 名称空间创建 list

spring 的 ioc 容器, 可以通过 util 名称空间创建 list

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

集合

应用案例:

(1)创建 BookStore.java

public class BookStore {//书店
    private List<String> bookList;
    public BookStore() {
    }
    public List<String> getBookList() {
        return bookList;
    }
    public void setBookList(List<String> bookList) {
        this.bookList = bookList;
    }
}

(2)修改 beans.xml , 增加配置

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

(3)测试

@Test
public void bookStoreTest() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    BookStore bookStore = ioc.getBean("bookStore", BookStore.class);
    System.out.println(bookStore.getBookList());
}

2.8 级联属性赋值

spring 的 ioc 容器, 可以直接给对象属性的属性赋值, 即级联属性赋值

应用案例:

(1)创建 Dept.java

public class Dept {
    private String name;
    public Dept() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

(2)创建 Emp.java

public class Emp {
    private String name;
    private Dept dept;
    public Emp() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
}

(3)修改 beans.xml , 增加配置

<!--配置Dept对象-->
<bean class="com.spring.bean.Dept" id="dept"/>
<!--配置Emp对象-->
<bean class="com.spring.bean.Emp" id="emp">
    <property name="name" value="jack"/>
    <property name="dept" ref="dept"/>
    <!--给dept的name属性指定值[级联属性赋值]-->
    <property name="dept.name" value="Java开发部门"/>
</bean>

2.9 通过静态工厂获取对象

在 spring ioc 容器, 可以通过静态工厂获取 bean 对象

应用案例:

(1)创建 MyStaticFactory.java

import java.util.HashMap;
import java.util.Map;

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 对象 -->
<bean id="my_monster" class="com.spring.factory.MyStaticFactory"
      factory-method="getMonster">
    <!-- constructor-arg 标签提供 key -->
    <constructor-arg value="monster_01"/>
</bean>

(3)测试

@Test
public void test02() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster = ioc.getBean("my_monster", Monster.class);
    System.out.println(monster);
}

2.10 通过实例工厂获取对象

在 spring ioc 容器, 可以通过实例工厂获取 bean 对象

 应用案例:

(1)建 MyInstanceFactory.java

import java.util.HashMap;
import java.util.Map;

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);
    }
}

(2)配置 beans.xml

<!-- 通过实例工厂来获取 bean 对象 -->
<bean id="myInstanceFactory" class="com.spring.factory.MyInstanceFactory"/>
<bean id="my_monster2" factory-bean="myInstanceFactory"
      factory-method="getMonster">
    <constructor-arg value="monster_02"/>
</bean>

(3)测试代码

@Test
public void getBeanByInstanceFactory() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster my_monster = ioc.getBean("my_monster2", Monster.class);
    System.out.println(my_monster);
}

(4)结果

2.11 通过 FactoryBean 获取对象

在 spring ioc 容器,通过 FactoryBean 获取 bean 对象

应用案例:

(1)创建MyFactoryBean.java

说明:

  • 该类实现了 FactoryBean 接口,并指定了泛型Monster
  • 创建了一个map集合,用于存放创建好的对象
  • 重写了getObject方法,返回keyVal对应的对象,即this.monster_map.get(keyVal)
  • 重写了getObjectType方法,返回对象的运行类型
  • 重写isSingleton方法,表示对象是否为单例,true为是
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;
    }
}

(2)配置 beans.xml

<!--
    1. 通过 FactoryBean 来获取 bean 对象
    2. name="keyVal" 就是 MyFactoryBean 定义的 setKeyVal 方法
    3. value="monster_01" ,就是给 keyVal 的值
-->
<bean id="myFactoryBean" class="com.spring.factory.MyFactoryBean">
    <property name="keyVal" value="monster_01"/>
</bean>

(3)测试代码

@Test
public void getBeanByFactoryBean() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster = ioc.getBean("myFactoryBean", Monster.class);
    System.out.println(monster);
}

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

在 spring ioc 容器中, 提供了一种继承的方式来实现 bean 配置信息的重用

应用案例:

(1)配置beans.xml

<!-- 继承的方式来实现 bean 配置信息的重用 -->
<bean id="monster10" class="com.spring.bean.Monster">
    <property name="monsterId" value="10"/>
    <property name="name" value="蜈蚣精"/>
    <property name="skill" value="蜇人"/>
</bean>
<!-- parent="monster10" 就是继承使用了 monster10 的配置信息 -->
<bean id="monster11" class="com.spring.bean.Monster" parent="monster10"/>
<!-- 当我们把某个bean设置为 abstract="true" 这个bean只能被继承,而不能实例化了 -->
<bean id="monster12" class="com.spring.bean.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.spring.bean.Monster" parent="monster12"/>

说明:

  • 可通过parent="monster10"方式继承其他bean,实现bean 配置信息的重用
  • 把某个bean设置为 abstract="true" ,这个bean只能被继承,而不能实例化了

测试代码:

@Test
public void getBeanByExtends() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster1 = ioc.getBean("monster11", Monster.class);
    System.out.println(monster1);
    Monster monster2 = ioc.getBean("monster13", Monster.class);
    System.out.println(monster2);
}

2.13 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)如果这样配置,表示 student01 对象依赖于 department01 对象

<bean id="student01" class="com.hspedu.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.hspedu.bean.Department" />

就会先创建 department01 对象,再创建 student01 对象.

(3)如果使用ref关联两个bean,无需关注配置顺序

说明:spring会先把有关联的对象都创建好,再处理引用关系

案例:

1. 先看下面的配置 , 两个 bean 创建的顺序如下
  • 先创建 id=memberDAOImpl
  • 再创建 id = memberServiceImpl
  • 调用 memberServiceImpl.setMemberDAO() 完成引用

2. 先看下面的配置 , 请问两个 bean 创建的顺序如下
  • 先创建 id = memberServiceImpl
  • 再创建 id=memberDAOImpl
  • 最后调用 memberServiceImpl.setMemberDAO() 完成引用

2.14 bean 对象的单例和多例

在 spring 的 ioc 容器, 默认是按照单例创建的,即配置一个 bean 对象后,ioc 容器只会创建一个 bean 实例。

如果,我们希望 ioc 容器配置的某个 bean 对象,是以多个实例形式创建的则可以通过配置 scope="prototype" 来指定,这样spring在获取对象时才会临时创建该对象,而不是像单例对象一样提前创建好

应用案例:

(1)创建 Car.java

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

(2)配置 beans.xml

<!-- 
如果希望 ioc 容器配置的某个 bean 对象,
是以多个实例形式创建可以通过配置 scope="prototype" 来指定
-->
<bean name="cat" scope="prototype" class="com.spring.bean.Cat"/>

(3)测试代码

@Test
public void getBeanByPrototype() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    for (int i = 0; i < 3; i++) {
        Cat cat = ioc.getBean("cat", Cat.class);
        System.out.println(cat);
    }
}

细节说明:

  • 在默认情况下 scope属性是 singleton,在启动容器时, 默认就会创建 , 并放入到 singletonObjects 集合
  • 在ioc容器中, 只有一个这个bean对象
  • 当执行getBean时, 返回的的是同一个对象
  • 如果我们希望每次getBean返回一个新的Bean对象,则可以scope="prototype"
  • 如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 , 可 以 指 定 懒 加 载
    lazy-init="true" (注意默认是 false)
  • 通常情况下, lazy-init 就使用默认值 false , 在开发看来, 用空间换时间是值得的, 除非
    有特殊的要求.
  • 如果 scope="prototype"  这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在
    getBean 时候,才创建对象.

2.15 bean 的生命周期

:bean 对象创建是由 JVM 完成的,依次执行如下方法:

(1)执行构造器
(2)执行 set 相关方法
(3)调用 bean 的初始化的方法(需要配置)
(4)使用 bean
(5)当容器关闭时候,调用 bean 的销毁方法(需要配置)
应用实例

(1)创建 House.java

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()..");
    }
}

(2)配置beans.xml,配置 bean 的初始化方法和销毁方法

<!-- 配置 bean 的初始化方法和销毁方法 -->
<bean id="house" class="com.spring.bean.House"
      init-method="init" destroy-method="destory">
    <property name="name" value="北京豪宅"/>
</bean>

(3)测试代码

@Test
public void beanLife() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    House house = ioc.getBean("house", House.class);
    System.out.println(house);
    //关闭容器
    ((ConfigurableApplicationContext) ioc).close();
}

细节说明:

  • 初始化 init 方法和 destory 方法, 是程序员来指定
  • 销毁方法就是当关闭容器时,才会被调用

2.16 配置 bean 的后置处理器

说明:

(1)在 spring ioc 容器,可以配置 bean 的后置处理器

(2)该处理器/对象会在 bean 初始化方法调用前和初始化方法调用后被调用

(3)程序员可以在后置处理器中编写自己的代码

应用案例:

(1)创 建 后 置处 理 器 MyBeanPostProcessor.java

public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
     * 在 bean 初始化之前完成某些任务
     * @param bean : 就是 ioc 容器返回的 bean 对象, 如果这里被替换会修改,则返
    回的 bean 对象也会被修改
     * @param beanName: 就是 ioc 容器配置的 bean 的名称
     * @return Object: 就是返回的 bean 对象
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
// TODO Auto-generated method stub
        System.out.println("postProcessBeforeInitialization 被 调 用 " + beanName + " bean= " + bean.getClass());
        return bean;
    }
    /**
     * 在 bean 初始化之后完成某些任务
     * @param bean : 就是 ioc 容器返回的 bean 对象, 如果这里被替换会修改,则返
    回的 bean 对象也会被修改
     * @param beanName: 就是 ioc 容器配置的 bean 的名称
     * @return Object: 就是返回的 bean 对象
     */
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessAfterInitialization 被调用 " + beanName + " bean= " + bean.getClass());
        return bean;
    }
}

0(2)配置beans03.xml

当我们在xml 容器配置文件 配置了 MyBeanPostProcessor,这时后置处理器对象,就会作用在该容器创建的所有Bean对象上

<!-- 配置 bean 的初始化方法和销毁方法 -->
<bean id="house" class="com.spring.bean.House"
      init-method="init" destroy-method="destory">
    <property name="name" value="北京豪宅"/>
</bean>
<!-- bean 后置处理器的配置 -->
<bean id="myBeanPostProcessor" class="com.spring.bean.MyBeanPostProcessor" />

(3)测试代码

@Test
public void testBeanPostProcessor() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");
    House house = ioc.getBean("house", House.class);
    System.out.println(house);
    //关闭容器
    ((ConfigurableApplicationContext) ioc).close();
}

疑惑点说明:

  • 怎么执行到这个方法:使用 AOP(反射+动态代理+IO+容器+注解)
  • 有什么用:可以对 IOC 容器中所有的对象进行统一处理 ,比如 日志处理/权限的校/安全的验证/事务管理.
  • 针对容器的所有对象吗:是的=>切面编程特点

2.17 通过属性文件给 bean 注入值

在 spring ioc 容器,通过属性文件给 bean 注入值

应用案例:

(1)resources/ 下创建my.properties

可以在Unicode编码转换 - 站长工具 (chinaz.com)网站将中文转成unicode编码

monsterId=1000
name=\u4e4c\u9f9f\u7cbe
skill=\u7f29\u8116\u5b50

(2)修改 src\beans.xml , 继续完成配置

location="classpath:my.properties" 表示在类路径下的my.properties读取

这时我们的属性值通过${属性名}获取,这里说的 属性名 就是 my.properties文件中的 k=v 的k

<!-- 
    1. 通过属性文件给 bean 注入值, 
    2. 需要导入: xmlns:context 名字空间,并指定属性文件路径
-->
<context:property-placeholder location="classpath:my.properties"/>
<bean id="monster100" class="com.spring.bean.Monster">
    <property name="monsterId" value="${monsterId}"/>
    <property name="name" value="${name}"/>
    <property name="skill" value="${skill}"/>
</bean>

(3)测试代码

@Test
public void setProByProFile() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
    Monster monster100 = ioc.getBean("monster100", Monster.class);
    System.out.println(monster100);
}

2.18 基于 XML bean 的自动装配

在 spring ioc 容器,可以实现自动装配 bean

应用案例:

(1)创建  OrderDao.java
public class OrderDao {
    public void saveOrder() {
        System.out.println("保存 一个订单...");
    }
}

创建 OrderService.java

public class OrderService {
    private OrderDao orderDao;
    public OrderDao getOrderDao() {
        return orderDao;
    }
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
}

创建 OrderAction.java

public class OrderAction {
    private OrderService orderService;
    public OrderService getOrderService() {
        return orderService;
    }
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}

(2)配置 beans.xml

根据类型进行自动组装

<!--
    autowire="byType" 表示根据类型进行自动组装.
-->
 <bean id="orderAction" autowire="byType" class="com.spring.action.OrderAction" />
 <bean id="orderService" autowire="byType" class="com.spring.service.OrderService"/>
 <bean id="orderDao" class="com.spring.dao.OrderDao"/>

根据名称进行自动组装

<!--
1. 说明: autowire = "byName" 会自动去找 id 为 setXxxx 后面 Xxxx 的 bean 自动组装.
,如果找到就装配,如果找不到就报错, 比如这里的
2. <bean id="orderAction" autowire="byName" class="com.spring.bean.OrderAction" />
就 会 去 找 OrderAction 类 中 定 义 的 setOrderService 的 id 为 orderService 的
OrderService bean 组装,找到就阻装,找不到就组装失败
-->
<bean id="orderAction" autowire="byName" class="com.spring.action.OrderAction"/>
<bean id="orderService" autowire="byName" class="com.spring.service.OrderService"/>
<bean id="orderDao" class="com.spring.dao.OrderDao"/>

说明:

(1)autowire="byType" 表示 在创建 orderService时通过类型的方式 给对象属性 自动完成赋值/引用

(2)比如OrderService 对象有 private OrderDao orderDao

(3)就会在容器中去找有没有 OrderDao类型对象

(4)如果有,就会自动的装配, 如果是按照 byType 方式来装配, 这个容器中,不能有两个OrderDao类型对象

(5)如果对象没有属性,  autowire就没有必要写

(6)如果设置的是 autowire="byName" 表示通过名字完成自动装配

(7)比如下面的 autowire="byName" class="com.hspedu.spring.service.OrderService"

  • 先看 OrderService 属性 private OrderDao orderDao
  • 再根据这个属性的setXxx()方法的 xxx 来找对象id(而不是根据属性名)
  • public void setOrderDao() 就会找id=orderDao对象来进行自动装配
  • 如果没有就装配失败

2.19 spring el 表达式

(1)Spring Expression Language,Spring 表达式语言,简称 SpEL。支持运行时查询并可以操 作对象。

(2)和 EL 表达式一样,SpEL 根据 JavaBean 风格的 getXxx()setXxx()方法定义的属性访问对象

(3)SpEL 使用#{…}作为定界符,所有在大框号中的字符都将被认为是 SpEL 表达式。

应用案例:

(1)创建 SpELBean.java

public class SpELBean {
    private String name;
    private Monster monster;
    private String monsterName;
    private String crySound;
    private String bookName;
    private Double result;
    public SpELBean() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Monster getMonster() {
        return monster;
    }
    public void setMonster(Monster monster) {
        this.monster = monster;
    }
    public String getMonsterName() {
        return monsterName;
    }
    public void setMonsterName(String monsterName) {
        this.monsterName = monsterName;
    }
    public String getCrySound() {
        return crySound;
    }
    public void setCrySound(String crySound) {
        this.crySound = crySound;
    }
    public String getBookName() {
        return bookName;
    }
    public void setBookName(String bookName) {
        this.bookName = bookName;
    }
    public Double getResult() {
        return result;
    }
    public void setResult(Double result) {
        this.result = result;
    }
    public String cry(String sound) {
        return "发出 " + sound + "叫声...";
    }
    public static String read(String bookName) {
        return "正在看 " + bookName;
    }
}

(2)配置 beans.xml

<!-- spring el 表达式 -->
<bean id="spELBean" class="com.spring.bean.SpELBean">
    <!-- sp el 给字面量 -->
    <property name="name" value="#{'小苏'}"/>
    <!-- sp el 引用其它 bean -->
    <property name="monster" value="#{monster01}"/>
    <!-- sp el 引用其它 bean 的属性值 -->
    <property name="monsterName" value="#{monster01.name}"/>
    <!-- sp el 调用普通方法(返回值) 赋值 -->
    <property name="crySound" value="#{spELBean.cry('喵喵的..')}"/>
    <!-- sp el 调用静态方法(返回值) 赋值 -->
    <property name="bookName" value="#{T(com.spring.bean.SpELBean).read(' 天龙八部')}"/>
    <!-- sp el 通过运算赋值 -->
    <property name="result" value="#{89*1.2}"/>
</bean>

<!--配置一个monster对象-->
<bean id="monster01" class="com.spring.bean.Monster">
    <property name="monsterId" value="100"/>
    <property name="name" value="蜈蚣精~"/>
    <property name="skill" value="蜇人~"/>
</bean>

(3)测试代码

@Test
public void setProBySpel() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");
    SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);
    System.out.println(spELBean.getName());
    System.out.println(spELBean.getMonster());
    System.out.println(spELBean.getMonsterName());
    System.out.println(spELBean.getCrySound());
    System.out.println(spELBean.getBookName());
    System.out.println(spELBean.getResult());
}

基于注解配置 bean

3.1 基本介绍

基于注解的方式配置 bean, 主要用于项目开发中的组件,比如 ControllerService、和 Dao.

组件注解的形式有:

(1)@Component 表示当前注解标识的是一个组件

(2)@Controller 表示当前注解标识的是一个控制器,通常用于 Servlet

(3)@Service 表示当前注解标识的是一个处理业务逻辑的类,通常用于 Service

(4)@Repository 表示当前注解标识的是一个持久化层的类,通常用于 Dao

3.2 快速入门案例

使用注解的方式来配置 Controller / Service / Respository / Component

(1)创建 UserAction.java UserService.java, UserDao.java MyComponent.java

/**
 * @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
 */
@Controller
public class UserAction {}
/**
 * @Service 标识该类是一个Service类/对象
 */
@Service
public class UserService {
}
/**
 * 使用 @Repository 标识该类是一个Repository是一个持久化层的类/对象
 */
@Repository
public class UserDao {
}
/**
 * @Component 标识该类是一个组件, 是一个通用的注解
 */
@Component
public class MyComponent {
}

(2)在xml文件中配置要扫描的包

<!--配置容器要扫描的包
1. component-scan 要对指定包下的类进行扫描, 并创建对象到容器
2. base-package 指定要扫描的包
3. 含义是当spring容器创建/初始化时,就会扫描com.spring.component包
   下的所有的 有注解 @Controller / @Service / @Respository / @Component类
   将其实例化,生成对象,放入到ioc容器
-->
<context:component-scan base-package="com.spring.component"/>

(3)测试代码

@Test
public void getBeanByAnnotation() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.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);
}

运行结果:

 (5)细节说明:

  • 必须在 Spring 配置文件中指定"自动扫描的包"IOC 容器才能够检测到当前项目中哪些类被标识了注解, 注意到导入 context 名称空间。可以使用通配符 * 来指定 ,比如 com.spring.* 表示。
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.spring.component" />
  • Spring IOC 容器不能检测一个使用了 @Controller 注解的类到底是不是一个真正的控
    制器。注解的名称是用于程序员自己识别当前标识的是什么组件。其它的 @Service
    @Repository 也是一样的道理( 也就是说 spring IOC 容器只要检查到注解就会生成对象,
    但是这个注解的含义 spring 不会识别,注解是给程序员编程方便看的)
  • <context:component-scan base-package="com.hspedu.spring.component" resource-pattern="User*.class" />,resource-pattern="User*.class": 表示只扫描com.spring.component 和它的子包下的User打头的类
  • 排除指定类

如果我们希望排除某个包/子包下的某种类型的注解,可以通过exclude-filter来指定

(1)context:exclude-filter 指定要排除哪些类
(2)type 指定排除方式 ,annotation表示按照注解来排除
(3)expression="org.springframework.stereotype.Service" 指定要排除的注解的全路径

<context:component-scan base-package="com.spring.component">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

以上配置表示不扫描带Service和Repository注解的类

  • 扫描指定类

如果我们希望按照自己的规则,来扫描包/子包下的某些注解, 可以通过 include-filter

(1)use-default-filters="false" 表示不使用默认的过滤机制/扫描机制(这个一定要有)
(2)context:include-filter 表示要去扫描哪些类
(3)type="annotation" 按照注解方式来扫描/过滤
(4)expression="org.springframework.stereotype.Service" 指定要扫描的注解的全路径

<context:component-scan base-package="com.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:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

 以上配置表示只扫描com.spring.component包下,带Service、Repository、Controller注解的类

  • 标记注解后,默认类名首字母小写作为 id 的值。也可以使用注解的 value 属性 指定 id 值,并且 value 可以省略。
@Controller(value="userAction01")

//value可以省略
@Controller("userAction01")

3.3 实现简单的 Spring 基于注解配置的程序

3.3.1 实现思路

3.3.2 代码实现

说明:以下实现代码基于上方入门案例中的四个类

(1)ComponentScan.java

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {

    //表示ComponentScan注解可以传入一个value属性
    String value() default "";
}

(2)建WwjSpringConfig.java

/**
 * 这是一个配置类,作用类似于原生Spring的 beans.xml 容器配置文件
 */
@ComponentScan(value = "com.spring.component")
public class WwjSpringConfig {
}

(3)建WwjSpringApplicationCo ntext.java

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.ConcurrentHashMap;

/**
 * 该类作用类似于Spring原生ioc容器
 */
public class WwjSpringApplicationContext {
    //拿到配置类.class文件
    private Class configClass;
    //ioc存放的就是通过反射创建的对象
    private final ConcurrentHashMap<String,Object> ioc = new ConcurrentHashMap<>();

    //构造器
    public WwjSpringApplicationContext(Class configClass){
        this.configClass = configClass;
//        System.out.println("this.configClass=" + this.configClass);
        //获取要扫描的包
        //1.先获取到ComponentScan注解
        ComponentScan componentScan = (ComponentScan)this.configClass.getDeclaredAnnotation(ComponentScan.class);
        //2.获取到注解的value值
        String path = componentScan.value();
//        System.out.println("要扫描的包= " + path);

        //得到要扫描的包下的所有class文件(在target目录下)
        //1.得到类的加载器
        ClassLoader classLoader = WwjSpringApplicationContext.class.getClassLoader();
        //2.通过类的加载器获取到要扫描的包的资源路径
        path = path.replace(".","/");//一定要把.替换成/
        URL resource = classLoader.getResource(path);
//        System.out.println(resource);
        //3.将要加载的资源(.class) 路径下的文件进行遍历
        File file = new File(resource.getFile());
        if (file.isDirectory()){
            File[] files = file.listFiles();
            for (File f : files) {
//                System.out.println(f.getAbsolutePath());
                //获取到.class文件的绝对路径
                String fileAbsolutePath = f.getAbsolutePath();
                //这里只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {
                    //获取到类全类名
                    //1.获取到类名
                    String className = fileAbsolutePath.substring
                            (fileAbsolutePath.lastIndexOf("\\") + 1, fileAbsolutePath.indexOf(".class"));
//                System.out.println(className);
                    //2.拼接成全类名
                    String classFullName = path.replace("/",".") + "." + className;
//                    System.out.println(classFullName);
                    //3.判断该类是不是需要注入容器,看该类是不是有注解 @Component @Service @Repository @Controller
                    try {
                        //这时,就得到了该类的Class对象
                        //1. Class clazz = Class.forName(classFullName) 可以反射加载类
                        //2. classLoader.loadClass(classFullName); 也可以反射类的Class
                        //3. 区别是 : 上面方式会调用该类的静态方法, 下面方法不会
                        //4. aClass.isAnnotationPresent(Component.class) 判断该类是否有 @Component
                        Class<?> aClass = classLoader.loadClass(classFullName);
                        //判断该类是否有 @Component @Service @Repository @Controller
                        if (aClass.isAnnotationPresent(Component.class) ||
                                aClass.isAnnotationPresent(Service.class) ||
                                aClass.isAnnotationPresent(Repository.class) ||
                                aClass.isAnnotationPresent(Controller.class)){
                            String keyVal = StringUtils.uncapitalize(className);
                            //获取到value值,替换指定id
                            if (aClass.isAnnotationPresent(Component.class)){
                                Component annotation = aClass.getDeclaredAnnotation(Component.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            } else if (aClass.isAnnotationPresent(Service.class)) {
                                Service annotation = aClass.getDeclaredAnnotation(Service.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            } else if (aClass.isAnnotationPresent(Repository.class)) {
                                Repository annotation = aClass.getDeclaredAnnotation(Repository.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            } else if (aClass.isAnnotationPresent(Controller.class)) {
                                Controller annotation = aClass.getDeclaredAnnotation(Controller.class);
                                String value = annotation.value();
                                if (!value.equals("")){
                                    keyVal = value;
                                }
                            }

                            //这时候就可以创建该类的对象,并放入到ioc容器中
                            Class<?> clazz = Class.forName(classFullName);
                            Object o = clazz.newInstance();
//                            String defaultID = className.substring(0,1).toLowerCase() + className.substring(1);
//                            System.out.println(defaultID);
                            //org.springframework.util.StringUtils包中的静态方法可以将字符串首字母小写
                            ioc.put(keyVal,o);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public Object getBean(String id){
        return ioc.get(id);
    }
}

(4)创建测试主程序WwjSpringApplicationContextTest.java

public class WwjSpringApplicationContextTest {
    public static void main(String[] args) {
        WwjSpringApplicationContext ioc = new WwjSpringApplicationContext(WwjSpringConfig.class);
        System.out.println(ioc.getBean("yss1"));
        System.out.println(ioc.getBean("yss2"));
        System.out.println(ioc.getBean("yss3"));
    }

(5)运行结果

3.4 自动装配

基于注解配置 bean,也可实现自动装配,使用的注解是:@AutoWired 或者 @Resource

3.4.1 @AutoWired 的规则说明

(1) IOC 容器中查找待装配的组件的 类型 ,如果有唯一的 bean 匹配,则使用该 bean
(2)如待装配的类型对应的 bean IOC 容器中有多个,则使用待装配的属性的属性名作
id 值再进行查找 , 找到就装配,找不到就抛异常

3.4.2 @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(name的值为属性名) 注入策略 , 如果匹配不上 ,
再使用 byType 策略 , 如果都不成功,就会报错
说明: @Autowired + @Qualifier(value = "userService02") 组合也可以完成指定 name/id 来进行自动装配,这时,是装配的 id=userService02 , 需要两个注解都需要写上

3.4.3 应用案例

(1)实现 UserAction UserService 的两级自动组装

@Service
public class UserService {
    //方法..
    public void hi(){
        System.out.println("UserService hi()~");
    }
}
/**
 * @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
 */
@Controller
public class UserAction {
    //@Autowired 自动装配 UserService, 这时是以 UserService,class 类型对对象进行组装
    //如待装配的类型对应的 bean 在 IOC 容器中有多个,则是以 id=userService 的 UserService 对象进行组装
    @Autowired
    private UserService userService;

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

    //不写这个方法,也可以完成组装
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

(2)测试代码

@Test
public void setProByAnnotationAutowired() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml");
    UserAction userAction01 = ioc.getBean(UserAction.class);
    userAction01.sayOk();
}

3.5 泛型依赖注入

基本说明:

(1)为了更好的管理有继承和相互依赖的 bean 的自动装配,spring 还提供基于泛型依赖的注入机制

(2)在继承关系复杂情况下,泛型依赖注入就会有很大的优越性

应用实例:

(1)各个类关系图

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

(3)创建 Book.java,Phone.java等类

package com.spring.depinjection;
public class Book {
}

package com.spring.depinjection;

public class Phone {
}

package com.spring.depinjection;

public abstract class BaseDao<T> {
    public abstract void save();
}

package com.spring.depinjection;
import org.springframework.stereotype.Repository;

@Repository
public class BookDao extends BaseDao<Book> {
    @Override
    public void save() {
        System.out.println("BookDao 的 save()");
    }
}

package com.spring.depinjection;
import org.springframework.stereotype.Repository;

@Repository
public class PhoneDao extends BaseDao<Phone> {
    @Override
    public void save() {
        System.out.println("PhoneDao 的 save()");
    }
}

package com.spring.depinjection;
import org.springframework.beans.factory.annotation.Autowired;

public class BaseService<T> {
    @Autowired
    private BaseDao<T> baseDao;
    public void save() {
        baseDao.save();
    }
}

package com.spring.depinjection;
import org.springframework.stereotype.Service;

@Service
public class BookService extends BaseService<Book> {
}

package com.spring.depinjection;
import org.springframework.stereotype.Service;

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

 (4)修改 beans06.xml , 增加配置

<context:component-scan base-package="com.hspedu.spring.depinjection"/>

(5)测试代码

@Test
public void setProByDepinjectionAutowired() {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("beans06.xml");
    BookService bookService = ioc.getBean(BookService.class);
    bookService.save();
    PhoneService phoneService = ioc.getBean(PhoneService.class);
    phoneService.save();
}

 (6)测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/611076.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

传输层之 TCP 协议

TCP协议段格式 源/目的端口号&#xff1a;表示数据是从哪个进程来&#xff0c;到哪个进程去。 序号&#xff1a;发送数据的序号。 确认序号&#xff1a;应答报文的序号&#xff0c;用来回复发送方的。 4 位首部长度&#xff1a;一个 TCP 报头&#xff0c;长度是可变的&#xff…

STM32学习和实践笔记(25):USART(通用同步、异步收发器)

一&#xff0c;STM32的USART简介 USART即通用同步、异步收发器&#xff0c;它能够灵活地与外部设备进行全双工数据交换&#xff0c;满足外部设备对工业标准 NRZ 异步串行数据格式的要求。 UART即通用异步收发器&#xff0c;它是在USART基础上裁剪掉了同步通信功能。 开发板上…

【Web】CTFSHOW 七夕杯 题解

目录 web签到 easy_calc easy_cmd web签到 CTF中字符长度限制下的命令执行 rce(7字符5字符4字符)汇总_ctf中字符长度限制下的命令执行 5个字符-CSDN博客7长度限制直接梭了 也可以打临时文件RCE import requestsurl "http://4ae13f1e-8e42-4afa-a6a6-1076acd08211.c…

Vision Mamba:高效视觉表示学习双向状态空间模型,超越Vision Transformer!

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; Vision Mamba: Efficient Visual Representation Learning with Bidirectional State Space Model 引言&#xff1a;探索视觉领域的新方向 在计算机视觉领域&…

翻工第二次 Ant Design Pro 下载,发现问题,电脑网络配置有误,魔法了

一、相关网址链接 鱼皮的用户中心项目 &#xff08;前端Ant Design Pro构建&#xff09; 语雀 ## 没有选择umi版本这一步 Issue #11144 ant-design/ant-design-pro GitHub 关于umi ui图标未显示问题_umi ui不出现-CSDN博客 二、存在问题 导致下载速度慢 本人镜像代码写…

双向链表(详解)

在单链表专题中我们提到链表的分类&#xff0c;其中提到了带头双向循环链表&#xff0c;今天小编将详细讲下双向链表。 话不多说&#xff0c;直接上货。 1.双向链表的结构 带头双向循环链表 注意 这几的“带头”跟前面我们说的“头节点”是两个概念&#xff0c;实际前面的在…

第十三届蓝桥杯决赛(国赛)真题 Java A 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 火柴棒数字试题 B: 小蓝与钥匙试题 C: 内存空间试题 D: 斐波那契数组试题 E: 交通信号试题 F: 数组个数试题 G: 六六大顺试题 H : \mathrm{H}: H: 选素数试题 I: 图书借阅试题 J \mathrm{J} J : 括号序列树 发现宝藏 前些天发现了一个…

数据分析:基于sparcc的co-occurrence网络

介绍 Sparcc是基于16s或metagenomics数据等计算组成数据之间关联关系的算法。通常使用count matrix数据。 安装Sparcc软件 git clone gitgithub.com:JCSzamosi/SparCC3.git export PATH/path/SparCC3:$PATHwhich SparCC.py导入数据 注&#xff1a;使用rarefy抽平的count ma…

stm32单片机学习路线

第一步 编程及硬件基础知识 1.掌握C语言基础 作为STM32的主要编程语言&#xff0c;C语言的基础知识是必不可少的。建议通过书籍、在线课程或者教学视频系统地学习C语言的基础知识&#xff0c;包括语法、数据类型、函数、指针等。 2.了解电子电路基础 对于单片机开发来说&…

经开区创维汽车车辆交接仪式顺利举行,守护绿色出行助力低碳发展

5月10日&#xff0c;“创维新能源汽车进机关”交车仪式于徐州顺利举行&#xff0c;20辆创维EV6 II正式交付经开区政府投入使用。经开区陈琳副书记、党政办公室副主任张驰主任、经开区公车管理平台苑忠民科长、创维汽车总裁、联合创始人吴龙八先生、创维汽车营销公司总经理饶总先…

OpenHarmony 实战开发——移植通信子系统

通信子系统目前涉及Wi-Fi和蓝牙适配&#xff0c;厂商应当根据芯片自身情况进行适配。 移植指导 Wi-Fi编译文件内容如下&#xff1a; 路径&#xff1a;“foundation/communication/wifi_lite/BUILD.gn” group("wifi") {deps [ "$ohos_board_adapter_dir/ha…

asp.net mvc使用IHttpModule拦截所有请求,包括资源文件

目录 HttpApplication 类 添加App_Code文件夹 MyHttpModel2 Web.config添加配置&#xff0c;在iis模块中生效 项目发布后&#xff0c;察看注册的自定义模块 框架集&#xff1a;.NET Framework 4.7web框架&#xff1a;asp.net mvc 5 HttpApplication 类 HttpApplication 类…

数据库备份与恢复--06---MySQL集群高可用架构之MHA

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 MySQL集群高可用架构之MHA1.什么是MHAMHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件 &#xff0c;m…

2024最新洗地机选购攻略!分享四款热门洗地机推荐

洗地机可以说是现代家庭生活中一大利器&#xff0c;它能帮我们快速搞定家里的地板清洁工作&#xff0c;省去了自己清洗滚刷的麻烦。不过&#xff0c;当下市面上洗地机品牌种类繁多&#xff0c;价格区间也相差悬殊&#xff0c;要选择一款性价比较高、使用体验较好的洗地机产品&a…

太阳能无人机的多元化应用

随着新能源技术的不断发展和成熟&#xff0c;太阳能在无人机的应用技术已经成熟。太阳能无人机得到了量产和广泛的应用。传统无人机相比&#xff0c;太阳能无人机无需燃油&#xff0c;运行费用低廉&#xff0c;搭载多种高科技设备&#xff0c;能够高效、多元化地采集和分析各类…

AI算法-高数3-导数-求导法则

P16 2.2 求导法则&#xff0c;宋浩老师&#xff1a;2.2 求导法则_哔哩哔哩_bilibili 反函数求导法则&#xff1a; 复合函数求导&#xff1a;剥洋葱法。

蜂群优化算法(bee colony optimization algorithm)

​注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 算法引言 自然界的启发&#xff1a;BSO算法的灵感来自于蜜蜂在自然界中的觅食行为。在自然界中&#xff0c;蜜蜂需要找到花蜜来生存。当一只蜜…

在做题中学习(53):寻找旋转数组中的最小值

153. 寻找旋转排序数组中的最小值 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;O(logn)->很可能就是二分查找 思路&#xff1a;再看看题目要求&#xff0c;可以画出旋转之后数组中元素的大小关系&#xff1a; 首先&#xff0c;数组是具有二段性的(适配二分查…

车载测试系列:UDS诊断服务

UDS诊断服务介绍 UDS&#xff08;Unified Diagnostic Services&#xff0c;统一诊断服务&#xff09;诊断协议诊断测试仪和ECU之间一种通信协议&#xff0c;在ISO14229中规定。UDS被用在几乎所有由OEM一级供应商所制造的新ECU。 诊断工具与车内的所有ECU均有连接&#xff0c;…

IO 5.10

在一个进程中&#xff0c;创建一个子线程。 主线程负责&#xff1a;向文件中写入数据 子线程负责&#xff1a;从文件中读取数据 要求使用线程的同步逻辑&#xff0c;保证一定在主线程向文件中写入数据成功之后&#xff0c;子线程才开始运行&#xff0c;去读取文件中的数据#incl…