Spring实战(第4版)学习(一)

Spring实战(第4版)学习

Spring实战(一)装配Bean

本章内容:

声明bean
构造器注入和Setter方法注入
装配bean
控制bean的创建和销毁

1.1 Spring配置的可选方案

描述bean如何进行装配时,Spring具有非常大的灵活性,它提供了三种主要的装配机制:
1.在XML中进行显式配置。
2.在Java中进行显式配置。
3.隐式的bean发现机制和自动装配。

1.2 自动化装配bean

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

1.组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
2.自动装配(autowiring):Spring自动满足bean之间的依赖。
创建可被发现的bean

@Component注解
这个注解表明该类会作为组件类,并告知Spring要为这个类创建bean。

package soundsystem;
import org.springframework.stereotype.Component;

@Component
public class SgtPeppers implements CompactDisc {

  private String title = "Sgt. Pepper's Lonely Hearts Club Band";  
  private String artist = "The Beatles";
  
  public void play() {
    System.out.println("Playing " + title + " by " + artist);
  }
}

@ComponentScan注解
这个注解能够在Spring中启用组件扫描。如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。
@Configuration
用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

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

@Configuration 
@ComponentScan
public class CDPlayerConfig { 
}

如果使用XML来启用组件扫描的话,那么可以使用Spring context命名空间的**context:component-scan**元素。

<context:component-scan base-package="soundsystem" />

如果@ComponentScan注解配置的话,可以通过basePackages属性对包进行配置,并且可为一个数组配置多个。

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

@Configuration
@ComponentScan"xxx","yyy"public class CDPlayerConfig { 
}

@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口,同样可数组。

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

@Configuration
@ComponentScan"com.xxx","com.yyy"public class CDPlayerConfig { 
}

@Autowired
自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。我们可以借助Spring的@Autowired注解,完成依赖注入的自动装配工作
通常在代码中使用了目前最常见的两种@Autowired方式:

1)属性注入的自动装配;
2)构造函数注入的自动装配;

以我自己为例,我周围最常用的是:属性注入,但是 Spring 团队建议使用的方式是:构造函数注入,当你使用属性注入时,鼠标移到属性上的 @Autowire 就可以看到如下图的提示,并且可以通过快捷键将属性注入直接修改成构造函数注入。

@Service
public class ConstructorServiceImpl implements ConstructorService {
 //个人理解:属性注入是通过在上下文中匹配到bean,注入进来完成装配工作
 //构造器注入,则是在一个地方通过调用构造器主动注入进来(可通过xml和config,后面会讲,没有主动注入会报错),这里完成装配工作。
 //也就是说一个是主动取,一个是别人主动给。
 
    // 1.属性注入,将匹配的bean装配给UserService对象
    @Autowired
    private UserService userService;
 
    private final DemoService demoService;
 
 
    // 2.构造函数注入
    @Autowired
    public ConstructorServiceImpl(DemoService demoService) {
        this.demoService = demoService;
    }
}

构造函数的常见优点是:

1.保证依赖不可变(final 关键字)
2.保证依赖不为空(省去了检查)
3.以完全初始化的状态返回到客户端(调用)代码
4.避免了循环依赖
5.提升了代码的可复用性

构造函数的常见缺点是:

1.构造函数会有很多参数。
2.有些类是需要默认构造函数的,一旦使用构造函数注入,就无法使用默认构造函数。
3.这个类里面的有些方法并不需要用到这些依赖。

@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false,没找到对应的bean就跳过。如果spring上下文中存在不止一个A类型的bean时,就会抛出异常;这里就会出现一种情况就是,当一个接口实现由两个实现类时,只使用@Autowired注解会报错。这时就需要使用@Qualifier注解搭配使用。

	@Autowired
	@Qualifier"Xxximp"private XxxService xxxService;

@Resource是按照名称装配的,上面的情况就可以直接使用@Resource指定名称,不需要@Qualifier。

通过Java代码装配bean

@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑。

@Configuration
public class CDPlayerConfig {
  
  @Bean(name="CompactDisc")
  public CompactDisc SgtPeppers() {
    return new SgtPeppers(); //new 的实现对象返回接口对象,这里创建CompactDisc bean
  }
  }

默认情况下,bean的ID与带有@Bean注解的方法名是一样的。在本例中,bean的名字将会是CompactDisc。如果你想为其设置成一个不同的名字的话,那么可以重命名该方法,也可以通过name属性指定一个不同的名字

借助JavaConfig实现注入

构造器注入

  @Bean("CDPlayer") //将返回的值注册为上下文中的bean
  public CDPlayer cdPlayer(CompactDisc compactDisc) {
    /*创建CDPlayer bean并将CompactDisc注入进去*/
    return new CDPlayer(compactDisc);
  }

Setter注入

@Bean("CDPlayer") //将返回的值注册为上下文中的bean
  public CDPlayer cdPlayer(CompactDisc compactDisc) {
   CDPlayer cDPlayer = new CDPlayer();
   cDPlayer.setCompactDisc(compactDisc);
    return cDPlayer;
  }

通过XML装配bean

这里没有太多需要解释的,只是按照xml的形势将java代码翻译了一次而已

导入和混合配置

导入

@import
引用于https://blog.csdn.net/pange1991/article/details/81356594
在应用中,有时没有把某个类注入到IOC容器中,但在运用的时候需要获取该类对应的bean,此时就需要用到@Import注解。示例如下:
先创建两个类,不用注解注入到IOC容器中,在应用的时候在导入到当前容器中。
1、创建Dog和Cat类
Dog类:

package com.example.demo;
 
public class Dog {
 
}

Cat类:

package com.example.demo;
 
public class Cat {
 
}

2、在启动类中需要获取Dog和Cat对应的bean,需要用注解@Import注解把Dog和Cat的bean注入到当前容器中。

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
 
//@SpringBootApplication
@ComponentScan
/*把用到的资源导入到当前容器中*/
@Import({Dog.class, Cat.class})
public class App {
 
    public static void main(String[] args) throws Exception {
 
        ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
        System.out.println(context.getBean(Dog.class));
        System.out.println(context.getBean(Cat.class));
        context.close();
    }
}

3、运行该启动类,输出结果:

com.example.demo.Dog@4802796d
com.example.demo.Cat@34123d65

从输出结果知,@Import注解把用到的bean导入到了当前容器中。

另外,也可以导入一个配置类
还是上面的Dog和Cat类,现在在一个配置类中进行配置bean,然后在需要的时候,只需要导入这个配置就可以了,最后输出结果相同。

MyConfig 配置类:

package com.example.demo;
import org.springframework.context.annotation.Bean;
 
public class MyConfig {
 
    @Bean
    public Dog getDog(){
        return new Dog();
    }
 
    @Bean
    public Cat getCat(){
        return new Cat();
    }
 
}

比如若在启动类中要获取Dog和Cat的bean,如下使用:

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
 
//@SpringBootApplication
@ComponentScan
/*导入配置类就可以了*/
@Import(MyConfig.class)
public class App {
 
    public static void main(String[] args) throws Exception {
 
        ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
        System.out.println(context.getBean(Dog.class));
        System.out.println(context.getBean(Cat.class));
        context.close();
    }
}

@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;

@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {
}
在XML配置中引用JavaConfig

假设希望将BlankDisc bean拆分到自己的配置文件中,该文件名为cd-config.xml,这与我们之前使用@ImportResource是一样的。我们可以在XML配置文件中使用元素来引用该文件,
元素只能导入其他的XML配置文件,并没有XML元素能够导入JavaConfig类。但是,有一个你已经熟知的元素能够用来将Java配置导入到XML配置中:元素。为了将JavaConfig类导入到XML配置中,我们可以这样声明bean:

<bean class = "soundsystem.CDConfig" />

附加

java普通类调用bean

主要是获取ApplicationContext上下文,再从中获取bean。
以下代码引用与某篇文章,忘记了。

package com.casic.springbook.soundsystem;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * Description:普通类调用Spring bean对象。说明:此类需要放到App.java同包或者子包下才能被扫描,否则失效。
 * 
 */
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringContextUtil.applicationContext == null){
            SpringContextUtil.applicationContext  = applicationContext;
        }
        System.out.println("---------------------------------------------------------------------");
        System.out.println("---------------------------------------------------------------------");
        System.out.println("---------------com.richfit.ruiche.util.SpringContextUtil---------------------------");
        System.out.println("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="+SpringContextUtil.applicationContext+"========");
        System.out.println("---------------------------------------------------------------------");
    }
    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }
    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }
    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}

测试类

public class Test {
    public void test(){
        /*普通方法调用bean中的方法,主要是获取ApplicationContext(上下文),再从中获取bean*/
        MediaPlayer mediaPlayer = (MediaPlayer)SpringContextUtil.getApplicationContext().getBean("CDPlayer");
        mediaPlayer.play();
    }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值