Spring - 02 - 自动化装配Bean


上面一篇文章中,学习了"Spring - 01 - 通过XML装配Bean",下面学习自动化装配Bean


自动化装配Bean


Spring从两个角度来实现自动化装配

组件扫描:Spring会自动发现应用上下文中所创建的bean

自动装配:Spring自动满足bean之间的依赖


一、创建可被发现的bean

直接上代码

package com.test.spring.server.test4;

/**
 * Created by CYX on 2018/4/17.
 */
public interface CompactDisc {

    void play();

}
package com.test.spring.server.test4;

import org.springframework.stereotype.Component;

/**
 * @author CYX
 * @create 2018-04-17-20:47
 */
//该注解表明该类会作为组件类,并告知Spring要为这个类创建bean。
@Component
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}
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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <context:component-scan base-package="com.test.spring.server.test4"/>

</beans>

通过XML启用组件扫描

测试主类

package com.test.spring.server.test4;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试组件扫描
 *
 * @author CYX
 * @create 2018-04-17-21:08
 */
public class Test4App {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("/spring/test4/applicationContext.xml");

        SgtPeppers sgtPeppers = context.getBean("sgtPeppers",SgtPeppers.class);

        sgtPeppers.play();
    }

}
输出结果:


和之前 在XML中显示配置Bean(Spring - 01 - 通过XML装配Bean) 对比一下,我们并没有在applicationContext.xml配置文件中配置<bean>元素用来显示的声明bean。

只是在需要创建bean对象的类上增加了一个注解@Component。

@Component注解的作用是 把普通pojo对象 实例化到Spring容器中,相当于applicationContext.xml配置文件中的:

<bean id="sgtPeppers" class="com.test.spring.server.test4.SgtPeppers"></bean>
Spring Framework 5.0.5.RELEASE API  的解释:
Indicates that an annotated class is a "component". 
Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning.
表示注释类是“组件”。
当使用基于注释的配置和类路径扫描时,这些类被认为是自动检测的候选对象。

当我们的类不属于各种归类时,我们就可以使用@Component来标注这个类。被标注的类,可以认为是"组件"

不过这里要注意,仅仅使用@Component注解时,我们并没有指定bean 的id,默认使用类名的首字母小写。

<context:component-scan>配置的作用是 开启组件自动扫描

<context:component-scan base-package="com.test.spring.server.test4"/>的含义是,扫描com.test.spring.server.test4包下的所有注解。



二、为组件扫描的bean命名

Spring应用 上下文 中所有的bean都会给定一个id。

在前面的例子中,我们并没有明确的为 SgtPeppers 指定 bean-id;

但Spring会为其指定一个id,具体的讲,这个bean所给定的id,为 sgtPeppers,也就是将类名的第一个字母变为小写。

如果要为这个bean设置不同的bean-id,需要将 期望id 作为值,传递给@Component注解。

例如:

@Component("sssgtPeppers")
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}
修改下主方法的bean id,其他不用修改,看下运行结果:



还有一种为bean命名的方式,这种方式不使用@Component注解,而是使用Java依赖注入规范所提供的的@Named注解来设置。

注意:使用@Named注解,需要添加依赖

<dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
</dependency>
@Named("test4-sgtPeppers")
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}

修改下主方法代码,看下运行结果:


Spring支持将@Named作为@Component注解的替代方案。

不过还是推荐@Component注解



三、使用Java Config自动装配Bean

在上面代码的基础上修改一下

package com.test.spring.server.test4;

/**
 * Created by CYX on 2018/4/17.
 */
public interface CompactDisc {

    void play();

}
package com.test.spring.server.test4;


import javax.inject.Named;

/**
 * @author CYX
 * @create 2018-04-17-20:47
 */
//该注解表明该类会作为组件类,并告知Spring要为这个类创建bean。
//@Component("sgtPeppers")
//@Component("sssgtPeppers")
@Named("test4-sgtPeppers")
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }
}
package com.test.spring.server.test4;

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

/**
 * 类CDPlayerConfig通过Java代码定义了Spring的装配规则。
 * <p>
 * 在后面我们再详细介绍
 * <p>
 * 这里,我们只需要观察一下CDPlayerConfig类并没有显示的声明任何bean。
 * <p>
 * 只不过它使用了@ComponentScan注解,这个注解能够在Spring中启用组件扫描。
 * <p>
 * 如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。
 * <p>
 * Spring将会扫描这个包以及这个包下所有的子包,查找带有@Component注解的类。
 *
 * 这种方式,我们暂时注释掉,使用XML来开启组件扫描。
 *
 * @author CYX
 * @create 2018-04-17-20:57
 */
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test4")
public class CDPlayerConfig {
}
package com.test.spring.server.test4;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 测试组件扫描
 *
 * @author CYX
 * @create 2018-04-17-21:08
 */
public class Test4App {


    public static void main(String[] args) {

//        ApplicationContext context = new ClassPathXmlApplicationContext("/spring/test4/applicationContext.xml");

        ApplicationContext context =new AnnotationConfigApplicationContext(CDPlayerConfig.class);
        SgtPeppers sgtPeppers = context.getBean("test4-sgtPeppers",SgtPeppers.class);

        sgtPeppers.play();

    }

}

注意:这里我并没有使用applicationContext.xml,将之前XML配置文件中的

<context:component-scan base-package="com.test.spring.server.test4"/>注释掉,所以并没有贴出来。

输出结果:


创建Java Config类的关键在于为其添加@Configuration注解。
@Configuration注解表明这个类是一个配置类,该类应该包含在Spring应用上下文中如何创建bean的细节。


@ComponentScan注解默认会扫描与配置类相同的包,以及这个包下面所有的子包。

然后查找带有@Component注解,找到的话,就会为他们创建bean实例。



四、通过为bean添加注解实现自动装配

自动装配就是让Spring自动满足bean依赖的一种方法;

在满足依赖的过程中,会在Spring应用上下文中寻找某个bean需求的其他bean。

为了声明要进行自动装配,可以借助Spring 的@Autowired注解

代码优先

package com.test.spring.server.test05;

/**
 * Created by CYX on 2018/4/17.
 */
public interface CompactDisc {

    void play();

}
package com.test.spring.server.test05;

import org.springframework.stereotype.Component;

/**
 * @author CYX
 * @create 2018-04-30-17:09
 */
@Component
public class SayHello {

    public SayHello() {
        System.out.println("SayHello 默认构造器");
    }

    public void sayHelloWithName() {
        System.out.println("SayHello :hello cyx");
    }

    public void sayHelloWithAddress() {
        System.out.println("SayHello :hello 南京");
    }

}
package com.test.spring.server.test05;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author CYX
 * @create 2018-04-17-20:47
 */
@Component("sssgtPeppers")
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

//    @Autowired
    private SayHello sayHello;

    /*@Autowired
    public void setSayHello(SayHello sayHello) {
        this.sayHello = sayHello;
    }*/

    @Autowired
    public SgtPeppers(SayHello sayHello) {
        this.sayHello = sayHello;
    }

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
        sayHello.sayHelloWithAddress();
        sayHello.sayHelloWithName();
    }
}
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:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">


    <context:component-scan base-package="com.test.spring.server.test05"/>

</beans>

主方法

package com.test.spring.server.test05;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试组件扫描
 *
 * @author CYX
 * @create 2018-04-17-21:08
 */
public class Test5App {


    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("/spring/test05/applicationContext05.xml");

        SgtPeppers sgtPeppers = context.getBean("sssgtPeppers", SgtPeppers.class);

        sgtPeppers.play();

    }

}

运行结果:


@Autowired 注解不仅可以放在成员变量、setter方法上,还可以放在构造器上。



五、通过Java代码装配Bean

在上面,我们已经初步使用过通过Java Config来装配Bean,下面详细的了解一下。

代码优先:

package com.test.spring.server.test06;

/**
 * Created by CYX on 2018/4/17.
 */
public interface CompactDisc {

    void play();

}
package com.test.spring.server.test06;


/**
 * @author CYX
 * @create 2018-04-17-20:47
 */
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";


    public SgtPeppers() {
    }

    public SgtPeppers(String title, String artist) {
        this.title = title;
        this.artist = artist;
    }

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }
}
package com.test.spring.server.test06;

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

/**
 * @author CYX
 * @create 2018-04-17-20:57
 */
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test06")
public class CDPlayerConfig {

    @Bean(name = "sssgtPeppers")
    public SgtPeppers initializationSgtPeppers() {
        return new SgtPeppers("888888","99999");
    }

}

主方法

package com.test.spring.server.test06;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 测试组件扫描
 *
 * @author CYX
 * @create 2018-04-17-21:08
 */
public class Test6App {


    public static void main(String[] args) {

        ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
        SgtPeppers sgtPeppers = context.getBean("sssgtPeppers", SgtPeppers.class);

        sgtPeppers.play();

    }

}

主方法


注意:

SgtPeppers类中已经没有 @Component 注解了。

SgtPeppers类 的实例化,在 CDPlayerConfig类中实现。

@Bean注解 会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中的bean。

@Bean(name = "sssgtPeppers") 同时,我们还为bean 设置了id。

在默认情况下,bean 的id 与带有@Bean注解的方法名是一样的。


在CDPlayerConfig类中进行bean 实例化的时候,咱们还可以对它进行一些初始化的操作。

这些都是根据业务来看...我这里模拟的话,只是,传入两个参数。



六、借助Java Config实现注入

代码优先

package com.test.spring.server.test06;

/**
 * Created by CYX on 2018/4/17.
 */
public interface CompactDisc {

    void play();

}
package com.test.spring.server.test06;

/**
 * @author CYX
 * @create 2018-04-30-17:09
 */
public class SayHello {

    public SayHello() {
        System.out.println("SayHello 默认构造器");
    }

    public void sayHelloWithName() {
        System.out.println("SayHello :hello cyx");
    }

    public void sayHelloWithAddress() {
        System.out.println("SayHello :hello 南京");
    }

}
package com.test.spring.server.test06;


import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author CYX
 * @create 2018-04-17-20:47
 */
public class SgtPeppers implements CompactDisc {

    private String title = "Sgt. Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

    @Autowired
    private SayHello sayHello;


    public SgtPeppers() {
    }

    public SgtPeppers(SayHello sayHello) {
        this.sayHello = sayHello;
    }

    public SgtPeppers(String title, String artist) {
        this.title = title;
        this.artist = artist;
    }

    @Override
    public void play() {
        System.out.println("Playing " + title + " by " + artist);
        sayHello.sayHelloWithAddress();
        sayHello.sayHelloWithName();
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }
}
package com.test.spring.server.test06;

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

/**
 * @author CYX
 * @create 2018-04-17-20:57
 */
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test06")
public class CDPlayerConfig {

    @Bean(name = "sssgtPeppers")
    public SgtPeppers initializationSgtPeppers() {
        return new SgtPeppers("888888", "99999");
    }

    @Bean
    public SgtPeppers initializationSgtPeppersWithHello() {
        return new SgtPeppers(initializationSayHello());
    }

    @Bean
    public SayHello initializationSayHello() {
        return new SayHello();
    }

}
package com.test.spring.server.test06;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 测试组件扫描
 *
 * @author CYX
 * @create 2018-04-17-21:08
 */
public class Test6App {


    public static void main(String[] args) {

        ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
        SgtPeppers sgtPeppers = context.getBean("sssgtPeppers", SgtPeppers.class);

        sgtPeppers.play();

    }

}
运行结果:

在CDPlayerConfig类中我们增加了两个bean,一个是用来注入的,另一个是被注入的。

在initializationSgtPeppersWithHello()方法中,并没有像之前那样子,传入参数,而是传入一个对象(方法)

看起来,SayHello对象,是通过调用initializationSayHello()方法得来的,但情况并非如此。

因为 initializationSayHello()方法上添加了@Bean注解,Spring将会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用。


Java Config类换一种写法:

package com.test.spring.server.test06;

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

/**
 * @author CYX
 * @create 2018-04-17-20:57
 */
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test06")
public class CDPlayerConfig {

    @Bean(name = "sssgtPeppers")
    public SgtPeppers initializationSgtPeppers() {
        return new SgtPeppers("888888", "99999");
    }

    @Bean
    public SgtPeppers initializationSgtPeppersWithHello(SayHello sayHello) {
        return new SgtPeppers(sayHello);
    }

    @Bean
    public SayHello initializationSayHello() {
        return new SayHello();
    }

}

在这里,initializationSgtPeppersWithHello(SayHello sayHello) 方法直接将对象传入,这样子,好理解一点。


参考文章:

https://www.cnblogs.com/Ming8006/p/6323633.html

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html

《Spring 实战》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值