【Spring】学习笔记07-Bean自动装配

自动装配是Spring满足bean依赖的一种方式!

Spring会在上下文中自动寻找,并自动给bean装配属性!

 

在Spring中有三种装配的方式:

1.在xml中显式的配置

pojo类

public interface makevoice {
    public void makevoice();
}
/**
 * @author 王广元
 */
@Data
public class Cat implements makevoice{
    @Override
    public void makevoice() {
        System.out.println("miao miao");
    }
}
/**
 * @author 王广元
 */
@Data
public class Dog implements makevoice{
    @Override
    public void makevoice() {
        System.out.println("wang wang");
    }
}
@Data
@NoArgsConstructor
public class People {
    private Cat cat;
    private Dog dog;
    private String name;
}

 

ApplicationContext.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="cat" class="com.wang.pojo.Cat"/>
    <bean id="dog" class="com.wang.pojo.Dog"/>
    <bean id="people" class="com.wang.pojo.People" p:cat-ref="cat" p:dog-ref="dog" p:name="王广元"/>
</beans>

单元测试

@Test
    public void test01(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Object people = context.getBean("people");
        System.out.println(people.toString());
    }
//测试结果:People(cat=Cat(), dog=Dog(), name=王广元)

 

 

2.在java中显示配置

 

 

 

3.隐式地自动装配bean【重要】

1.byName

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="cat" class="com.wang.pojo.Cat"/>
    <bean id="dog" class="com.wang.pojo.Dog"/>

    <bean id="people1" class="com.wang.pojo.People" autowire="byName">
        <property name="name" value="poeple1_autowire_byName"/>
    </bean>
</beans>

我们通过设置autowire参数,此时为byName,通过注册bean的id实现自动装配,Spring容器会自动在容器上下文中查找和自己对象set方法后面的值对应的bean id,

找到id=cat and id=dog的bean,并将其装配到id=people1的bean中

单元测试

   @Test
    public void test03(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        People people1 = (People) context.getBean("people1");
        System.out.println(people1.toString());
    }
//测试结果:People(cat=Cat(), dog=Dog(), name=poeple1_autowire_byName)


 

2.byType

<!--    bytype:会自动查找容器上下文中,和自己对象属性相同的bean-->
    <bean id="people2" class="com.wang.pojo.People" autowire="byType">
        <property name="name" value="people+autowire_bytype"/>
    </bean>

缺点:bean上下文中只允许注册class类的一个bean,当注册多个时,会报错

单元测试

 @Test
    public void test02(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        People people2 = (People) context.getBean("people2");
        System.out.println(people2.toString());
    }

小结:

  • byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set的值保持一致!
  • byname的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型保持一致!

4.使用注解实现自动装配

 

Are annotations better than XML for configuring Spring?

The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML. The short answer is “it depends.”
The long answer is that each approach has its pros and cons, and, usually, it is up to the developer to decide which strategy suits them better.
Due to the way they are defined, annotations provide a lot of context in their declaration, leading to shorter and more concise configuration.
However, XML excels at wiring up components without touching their source code or recompiling them.
Some developers prefer having the wiring close to the source while others argue that annotated classes are no longer POJOs and,
furthermore, that the configuration becomes decentralized and harder to control. No matter the choice, Spring can accommodate both styles and even mix them together. It is worth pointing out that through its JavaConfig option,
Spring lets annotations be used in a non-invasive way, without touching the target components source code and that, in terms of tooling,
all configuration styles are supported by the Spring Tools for Eclipse.

 

JDK1.5支持的注解,Spring就支持注解了

要使用注解须知:

导入约束

xmlns:context="http://www.springframework.org/schema/context"

 

配置注解的支持

 <context:annotation-config/>

 

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

@Autowired

直接在属性上使用(也可以应用在set方法上),

使用Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字(byType)

public @interface Autowired {
    boolean required() default true;
}

required=false,允许bean实例地属性值为null

测试实例:

pojo类

@Data
@NoArgsConstructor

public class People {
    //如果显示地定义了Autowired地requiref属性为false,证明这个对象可以为null
    @Autowired(required = false)
    private Cat cat;
    @Autowired(required = false)
    private Dog dog;
    private String name;

    public People(@Nullable String name) {
        this.name = name;
    }
}

单元测试

  @Test
    public void test05(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        People people3 = (People) context.getBean("people3");
        System.out.println(people3.toString());
    }
//测试结果
//People(cat=null, dog=null, name=测试@Autowired注解)

 

@Autowired+@Qu

ApplicationContext.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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:annotation-config/>
    <bean id="cat1" class="com.wang.pojo.Cat"/>
    <bean id="dog1" class="com.wang.pojo.Dog"/>
    <bean id="dog2" class="com.wang.pojo.Dog"/>
    <bean id="people3" class="com.wang.pojo.People">
        <property name="name" value="测试@Autowired注解"/>
    </bean>
</beans>

 

当存在多个相同class的bean存在于Spring容器中,我们可以使用@Qualifier(value=bean_id)手动指定相应属性注入的bean

@Data
@NoArgsConstructor

public class People {
    //如果显示地定义了Autowired地requiref属性为false,证明这个对象可以为null
    @Autowired(required = false)
    private Cat cat;
    @Autowired(required = false)
    @Qualifier(value = "dog2")
    private Dog dog;
    private String name;

    public People(@Nullable String name) {
        this.name = name;
    }
}

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成时,我们可以使用@Qualifier(value="xxx")去配置@Autowired的使用。

 

@Resource

POJO类

@Data
@NoArgsConstructor

public class People {
    //如果显示地定义了Autowired地requiref属性为false,证明这个对象可以为null
    @Resource(name="cat1")
    private Cat cat;
    @Resource
    private Dog dog;
    private String name;

    public People(@Nullable String name) {
        this.name = name;
    }
}

ApplicationContext.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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://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/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:annotation-config/>
    <bean id="cat1" class="com.wang.pojo.Cat"/>
    <bean id="cat2" class="com.wang.pojo.Dog"/>
    <bean id="dog1" class="com.wang.pojo.Dog"/>
    <bean id="dog2" class="com.wang.pojo.Dog"/>

    <bean id="people3" class="com.wang.pojo.People">
        <property name="name" value="测试@Autowired注解"/>
    </bean>
</beans>

单元测试

   @Test
    public void test05(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        People people3 = (People) context.getBean("people3");
        System.out.println(people3.toString());
    }

警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'people3': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.wang.pojo.Dog' available: expected single matching bean but found 3: cat2,dog1,dog2

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'people3': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.wang.pojo.Dog' available: expected single matching bean but found 3: cat2,dog1,dog2

此时beans.xml中存在多个Cat,Dog的注册bean,但id都不符合People类中set方法的值,因此会报错、

我们将cat1,dog1的beanid改为cat,dog

 <bean id="cat" class="com.wang.pojo.Cat"/>
 <bean id="dog" class="com.wang.pojo.Dog"/>

此时单元测试一切正常(测试结果)

People(cat=Cat(), dog=Dog(), name=测试@Autowired注解)

进程已结束,退出代码为 0

同样@Resource(name="xxx")可以通过name显示地指定bean

 

@Autowired和@Resource的区别

相同点:

都是作用于自动装配的

不同点:

@Autowired 是先 bytype然后byname(当存在多个相同class的bean时,需要借助@Qualifier注解手动指定相应的bean)

@Resource 也是先bytype然后byname

 

posted @ 2022-06-11 12:44  王广元  阅读(37)  评论(0编辑  收藏  举报
分享到: