Spring开发_IoC容器

Spring Framework主要包括几个模块:
支持IoC和AOP的容器;
支持JDBC和ORM的数据访问模块;
支持声明式事务的模块;
支持基于Servlet的MVC开发;
支持基于Reactive的Web开发;
以及集成JMS、JavaMail、JMX、缓存等其他模块。

IoC容器

容器是一种为某种特定组件的运行提供必要支持的软件环境。
使用容器运行组建,除了提供一个组件运行环境外,容器还提供了许多底层服务。
Spring的核心就是提供了一个IoC容器,它可以管理所有轻量级的Bean组件,提供的底层服务包括组件的生命周期的管理、配置和组装服务、AOP支持,以及建立在AOP基础上的声明式事务服务等。

IoC原理

控制反转,即由IoC容器控制组件的创建和配置。

public class BookService{
	private DataSource dataSource;
	public void setDataSource(DataSource dataSource){ //通过setDataSource()方法来注入DataSource
		this.dataSource = dataSource;
	}
	//public BookService(DataSource dataSource){ //也可通过构造方法注入
		this.dataSource = dataSource;
}

IoC又称为依赖注入,将组件的创建和配置与组件的使用相分离。

装配Bean

public class UserService {
    private MailService mailService;

    public void setMailService(MailService mailService) {
        this.mailService = mailService;
    }

application.xml配置文件告诉Spring的IoC容器如何创建并组装Bean:

 <bean id="userService" class="com.itranswarp.learnjava.service.UserService">
        <property name="mailService" ref="mailService" />
    </bean>

通过注入了一个Bean。

如果注入的不是Bean,而是boolean,int,String这样的数据类型,则通过value注入,如:

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
    <property name="username" value="root" />
    <property name="password" value="password" />
    <property name="maximumPoolSize" value="10" />
    <property name="autoCommit" value="true" />
</bean>

在主方法中加载配置文件,创建一个IoC容器实例,这样就能从Spring容器中取出装配好的Bean然后使用它。

Spring的IoC容器接口是ApplicationContext;
通过XML配置文件实现IoC容器时,使用ClassPathXmlApplicationContext;
持有IoC容器后,通过getBean()方法获取Bean的引用。

public class Main {
    public static void main(String[] args) {
    	ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
    	UserService userService = context.getBean(UserService.class); //根据Bean的类型获取Bean的引用
    	User user = userService.login("bob@example.com", "password");
        System.out.println(user.getName());
    }
}

另一种IoC容器叫BeanFactory,使用和ApplicationContext类似:

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("application.xml"));
MailService mailService = factory.getBean(MailService.class);

使用Annotation配置(更简单)

使用@Component注解相当于定义了一个Bean
使用@Aurowired相当于将指定类型的Bean注入到指定的字段中

@Component
public class UserService {
    MailService mailService;

    public UserService(@Autowired MailService mailService) {
        this.mailService = mailService;
    }
    ...
}

使用@Configuration表示它是一个配置类
使用@ComponentScan告诉容器,自动搜索当前类所在的包以及子包

最后编写一个AppConfig类启动容器:

@Configuration
@ComponentScan
public class AppConfig{
	public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = context.getBean(UserService.class);
        User user = userService.login("bob@example.com", "password");
        System.out.println(user.getName());
    }
}

定制Bean

1.Spring默认使用Singleton创建Bean,也可指定Scope为Prototype.

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // @Scope("prototype")
public class MailSession {
    ...
}

2.可将相同类型的Bean注入List。

@Component
public class NameValidator implements Validator{
	public void validate(String email, String password, String name){
	...}
}
@Component
public class EmailValidator implements Validator {
    public void validate(String email, String password, String name) {
    ...}
}
@Component
public class Validators{
	@Autowired
	List<Validator> validators;
	public void validate(String email, String password, String name){
		for(var validator: this.validators){
			validator.validate(email, password, name);
		}
	}
}

3.可用@Autowired(required=false)允许可选注入;

4.如果一个Bean不在自己的package管理之内,可用带@Bean标注的方法创建Bean;

@Configuration
@ComponentScan
public class AppConfig {
    // 创建一个Bean:
    @Bean
    ZoneId createZoneId() {
        return ZoneId.of("Z");
    }
}

5.可使用@PostConstruct和@PreDestroy对Bean进行初始化和清理;

@Component
public class MailService {
    @Autowired(required = false)
    ZoneId zoneId = ZoneId.systemDefault();

    @PostConstruct
    public void init() {
        System.out.println("Init mail service with zoneId = " + this.zoneId);
    }

    @PreDestroy
    public void shutdown() {
        System.out.println("Shutdown mail service");
    }
}

6.相同类型的Bean只能有一个指定为@Primary,其他必须用@Quanlifier(“beanName”)指定别名;

@Configuration
@ComponentScan
public class AppConfig {
    @Bean("z")
    ZoneId createZoneOfZ() {
        return ZoneId.of("Z");
    }

    @Bean
    @Qualifier("utc8")
    ZoneId createZoneOfUTC8() {
        return ZoneId.of("UTC+08:00");
    }
}

注入时,可通过别名@Quanlifier(“beanName”)指定某个Bean;

@Component
public class MailService {
	@Autowired(required = false)
	@Qualifier("z") // 指定注入名称为"z"的ZoneId
	ZoneId zoneId = ZoneId.systemDefault();
    ...
}

使用Resource(读取文件)

Spring提供了Resource类便于注入资源文件,它可以像String、int一样使用@Value注入,然后使用resouce.getInputStream()方法获取到输入流。

@Component
public class AppService{
	@Value("classpath:/logo.txt")
	private Resource resource;
	private String logo;

    @PostConstruct
    public void init() throws IOException {
        try (var reader = new BufferedReader(
                new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
            this.logo = reader.lines().collect(Collectors.joining("\n"));
        }
    }
}

注入配置(读取配置文件)

@PropertySource来自动读取配置文件

@Configuration
@ComponentScan
@PropertySource("app.properties")
public class AppConfig{
	@Value("${app.zone:Z}")//读取key为app.zone的value
	String zoneId;
	 @Bean
    ZoneId createZoneId() {
        return ZoneId.of(zoneId);
    }
}

还可以把注入的注解写到方法参数中:

@Bean
ZoneId createZoneId(@Value("{app.zone:Z}") String zoneId){
	return ZoneId.of(zoneId);
}

另一种注入配置的方法是通过一个简单的JavaBean持有所有的配置,例如一个SmtpConfig:

@Component
public class SmtpConfig {
    @Value("${smtp.host}")
    private String host;

    @Value("${smtp.port:25}")
    private int port;

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }
}

然后,在需要读取的地方,使用#{smtpConfig.host}注入:

@Component
public class MailService {
    @Value("#{smtpConfig.host}")
    private String smtpHost;

    @Value("#{smtpConfig.port}")
    private int smtpPort;
}

使用条件装配

创建某个Bean时,可以根据**@Profile来决定是否创建,表示不同的环境**
例如分别定义三种环境:开发、测试和生产

@Configuration
@ComponentScan
public class AppConfig {
    @Bean
    @Profile("!test")
    ZoneId createZoneId() {
        return ZoneId.systemDefault();
    }

    @Bean
    @Profile("test")
    ZoneId createZoneIdForTest() {
        return ZoneId.of("America/New_York");
    }
}

Spring还可以根据**@Conditional决定是否创建某个Bean。**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值