Spring IOC的组件注册、依赖注入的实现方式

IOC—Inversion of Control,控制反转,是一种设计思想它能指导程序员如何设计出松耦合、更优良的程序代码。

如果不用IOC,创建、销毁对象、对象之间的依赖关系,都需要程序员自己在代码里面体现,各种new。

而有了IOC容器后,代码里只需要定义对象的基本信息,并将它注册到IOC容器中,让IOC管理它的生命周期(创建和销毁)以及它们之间的依赖关系。

 

第一章:将组件(对象)添加到ioc容器的四种方式

        第一节:bean方式(注解和xml两种方式)

        第二节:bean工厂方式(静态工厂、实例化工厂两种)

        第三节:包扫描+@controller、@Service、@Repository@Component(注解和xml两种方式)

        第四节:@Import注解快速注册

        第五节(拓展):@Conditional 根据条件判断bean是否可以添加到容器中,Spring底层经常使用

        第六节(拓展):@profile 根据当前环境,动态的激活和切换一系列组件

第二章:自动装配实现方式(即DI 依赖注入实现属性赋值)

         第七节:@Autowired 自动装配

         第八节:JSR-250(java规范)的注解@Resource

         第九节:xml配置实现装配的多种方式

         第十节(拓展):自定义组件实现xxxAware接口,使用spring底层的一些组件(BeanFactory、ApplictionContext等)

       

          

 

Action one:创建maven项目,添加spring和junit依赖:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>4.3.12.RELEASE</version>
</dependency>

<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>

第一节:bean方式注册组件

>定义User对象

public class User {
	public User() {
		super();
	}
	public User(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	private String name;
	private Integer age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}

>xml方式实现注册

<bean id="user" class="com.mote.pojo.User">
     <property name="name" value="zhangsan"></property>
     <property name="age" value="22"></property>
</bean>

>注解方式实现注册

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.mote.pojo.User;

//@Configuration 标注这是一个注解配置类,该类就相当于spring的配置文件applictionContext.xml
@Configuration 
public class MainConfig {
	/**
	 * @Bean表示向IOC容器中注册bean,value指定bean名称,如果不指定,默认使用方法名
	 */
	@Bean(value="user")
	public User user(){
		return new User("lisi",25);
	}
}

>测试类

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mote.config.MainConfig;
import com.mote.pojo.User;

public class MainTest {
	
	@Test //注解测试
	public void testAnnotation(){
		
		//加载Spring注解配置类
		AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
		//从容器中获取bean
		User user = application.getBean(User.class);
		System.out.println(user);
	}
	
	@Test //xml测试
	public void testXml(){
		//加载Spring-xml配置文件
		ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
	    //从容器中获取bean
		User user = application.getBean(User.class);
		System.out.println(user);
	}
}

>打印结果:

第二节:bean工厂方式(静态工厂、实例化工厂两种)

1:静态工厂模式:工厂类本身不需要实例化, 通过工厂类直接调用其中的静态方法生成bean对象。

定义对象Car:

public class Car {
	private String name;
	private double money;
	public Car() {
		super();
	}
	public Car(String name, double money) {
		super();
		this.name = name;
		this.money = money;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getMoney() {
		return money;
	}
	public void setMoney(double money) {
		this.money = money;
	}
	@Override
	public String toString() {
		return "Car [name=" + name + ", money=" + money + "]";
	}
	
}

定义生产Car的静态工厂:

public class CarFactory {
	/**
	 * 静态方法,返回Car实例
	 * @return
	 */
	public static Car getCar(){
		return new Car("宝马",10000000.00);
	}

}

配置xml:

<!-- 配置Car工厂,调用getCar(),返回Car实例 -->
<bean id="car" class="com.mote.pojo.CarFactory" factory-method="getCar"></bean>

测试打印:

public class MainTest {
	@Test //注解测试
	public void testAnnotation(){
		ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
		Car car = application.getBean(Car.class);
		//Car car1 = (Car) application.getBean("car");
		System.out.println(car);
	}
}

2:实例工厂模式:因为getCar方法不是静态的,需要先实例化CarFactory工厂,在通过carFactory调用getCar生产bean对象

定义对象Car:(和静态工厂模式的测试一致)

定义Car的实例化工厂:

public class CarFactory {
	
	public Car getCar(){
		return Car("宝马",10000000.00);
	}

}

配置xml:

<!-- 配置Car工厂-->
<bean id="carFactory" class="com.mote.pojo.CarFactory"></bean>

<!-- 调用carFactory的getCar,配置car的实例  -->
<bean id="car" factory-bean="carFactory" factory-method="getCar"></bean>

测试打印:(和静态工厂模式的测试一致)

第三节:包扫描+@controller、@Service、@Repository@Component(注解和xml两种方式)

>定义UserController,UserService,UserDao,UserTest,分别加上述注解

>项目目录结构:

>xml方式实现包扫描注册

<!-- 开启包扫描 ,指定的包以及子包下 只要标注了@Controller、@Service、@Repositoy、@Component
     的类都会被添加到spring容器中-->
<context:component-scan base-package="com.mote"/>

>注解方式实现包扫描注册

@Configuration
//@ComponentScan 开启包扫描,value指定包名
@ComponentScan(value = "com.mote")
public class MainConfig {
	
}

>测试类

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mote.config.MainConfig;

public class MainTest {
	@Test //注解测试
	public void testAnnotation(){
		//加载Spring注解配置类
		AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
		
		//获取注册到容器中的组件name集合,遍历打印
		String[] names = application.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
	
	@Test //xml测试
	public void testXml(){
		//加载Spring-xml配置文件
		ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
		
		String[] names = application.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
}

>打印结果

第四节:@Import注解快速注册

Import注解实现注册有三种实现方式

1:@Import(要添加的组件)

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.mote.dao.UserDao;
import com.mote.service.UserService;

@Configuration
//@Import 快速给容器中导入一个组件,默认id是全类名
//@Import(UserController.class)     //注册一个
@Import({UserService.class,UserDao.class})   //注册多个
public class MainConfig {
	
}

2:实现ImportSelector接口,自定义返回要注册的组件

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImport implements ImportSelector {

	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		return new String[] { "com.mote.controller.UserService","com.mote.dao.UserDao" };
	}

}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(MyImport.class)
public class MainConfig {
	
}

3:实现ImportBeanDefinitionRegistrar接口,实现手动注册

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import com.mote.dao.UserDao;

public class MyImport implements ImportBeanDefinitionRegistrar {

	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:BeanDefinition注册类
	 */
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata,
			BeanDefinitionRegistry registry) {
		//判断容器中是否注册userDao
		boolean flag = registry.containsBeanDefinition("userDao");
		
		//向容器中注册bean,并指定bean_name为userDao
		BeanDefinition beanDefinition = new RootBeanDefinition(UserDao.class);
		registry.registerBeanDefinition("userDao", beanDefinition );
	}

}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(MyImport.class)
public class MainConfig {
	
}

>测试类

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.mote.config.MainConfig;

public class MainTest {
	@Test //注解测试
	public void testAnnotation(){
		//加载Spring注解配置类
		AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
		
		//获取注册到容器中的组件name集合,遍历打印
		String[] names = application.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
}

>打印结果

方式一:

方式二:

方式三:

第五节(拓展):@Conditional 根据条件判断bean是否可以添加到容器中,Spring底层经常使用

需求描述:如果当前系统是Windows,注册User(“bier”,30),反之不注册

1:实现Condition接口,书写判断逻辑

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class MyConditional implements Condition{
	/**
	 * ConditionContext:判断条件使用的上下文
	 * AnnotatedTypeMetadata:注释信息
	 */
	public boolean matches(ConditionContext context,
			AnnotatedTypeMetadata metadata) {
		//获取当前运行环境信息
		Environment environment = context.getEnvironment();
		//获取当前系统类型,判断是否是Windows
		String type = environment.getProperty("os.name");
	    return type.contains("Windows")?true:false;

	}

}

2:使用@Conditional注解进行判断

import com.mote.pojo.User;

@Configuration
public class MainConfig {
	
	@Bean
	@Conditional({MyConditional.class})
	public User bier(){
		return new User("bier",30);
	}
	
}

小技巧:eclipse模拟linux环境

测试类中点击鼠标右键,Run AS  >   RunConfigurations

测试:

public class MainTest {
	@Test //注解测试
	public void test(){
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] names = context.getBeanDefinitionNames(); //打印spring容器注册的bean名称
        for (String name : names) {
			System.out.println(name);
		}
	}
}

windows环境运行结果打印:

linux系统运行结果打印:

 第六节(拓展):@profile 根据当前环境,动态的激活和切换一系列组件

 案例功能描述:根据当前环境决定使用相应的数据库
 * 默认情况下:数据库A
 * 测试环境下:数据库B
 * 开发环境下:数据库C

导入maven:dhcp连接池和mysql驱动

<dependency>
	<groupId>commons-dbcp</groupId>
	<artifactId>commons-dbcp</artifactId>
	<version>1.4</version>
</dependency>

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>6.0.6</version>
</dependency>

案例代码:

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

/**
 * @Profile:加了该环境标识的bean,只有这个环境被激活后后才能注册到容器
 */
@Configuration
public class MainConfig {
	
	@Bean
	@Profile("default")   //不指定的情况下,默认使用的数据库
	public BasicDataSource dataSourceDefault() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setUrl("jdbc:mysql://localhost:3306/A");
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		return dataSource;
	}

	@Bean
	@Profile("test")   //测试环境
	public BasicDataSource dataSourceTest() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setUrl("jdbc:mysql://localhost:3306/B");
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		return dataSource;
	}
	
	@Bean
	@Profile("devlop")   //开发环境
	public BasicDataSource dataSourceDev() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setUrl("jdbc:mysql://localhost:3306/C");
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		return dataSource;
	}
	
}

测试代码:

public class MainTest {
	@Test //注解测试
	public void test(){
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
		String[] names = context.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
}

测试一:不指定环境变量,直接运行,打印如下

测试二:指定环境为test,运行打印

打印结果:

  第七节:@Autowired 自动装配

                @Autowired使用前提,userService已经注册到spring容器中

@Autowired实现装配的三种操作方式

1)标注在属性上

/**
	 * @Autowired 首先根据UserService类型去容器寻找Bean,
	 * 如果这个类型有多个Bean,比如userService/userService1
	 * 那么@Autowired就会根据属性名称userService去匹配.
	 * 
	 * 另外,可以使用注解@Qualifier配合@Autowired使用,用于指定容器中特定id的Bean
	 */
	//@Qualifier("userService")
	@Autowired
	private UserService userService;

2)标注在set方法上

private UserService userService;

@Autowired
public void setUserService(UserService userService) {
	this.userService = userService;
}

3)标注在构造器上

private UserService userService;
	
/**
* 如果该类只有这一个构造器,那么这个@Autowired注解可以省略不写
* 因为spring容器生成的时候,就必须根据这个构造器去创建对象
*/
@Autowired
public UserController(UserService userService) {
	super();
	this.userService = userService;
}

 第八节:JSR-250(java规范)的注解@Resource

                  @Resource使用前提,userService已经注册到spring容器中  

/**
* @Resource JSR-250注解,用来激活资源,通过name属性,指定容器中特定id的bean
*/
@Resource(name="userService")
private UserService userService;

第九节:xml配置实现装配的多种方式

                

1)set方法注入依赖

xml:

<bean id="userService" class="com.mote.service.UserService"/>
     
<bean class="com.mote.controller.UserController">
   <property name="userService" ref="userService"/>
</bean>

代码:

private UserService userService;

public void setUserService(UserService userService) {
	this.userService = userService;
}

2)构造器注入依赖

xml:

<bean id="userService" class="com.mote.service.UserService"></bean>

<bean class="com.mote.controller.UserController">
     <constructor-arg name="userService" ref="userService"></constructor-arg>
</bean>

代码:

private UserService userService;
	
public UserController(UserService userService) {
	this.userService = userService;
}

3)静态工厂注入依赖和实例化工厂注入依赖

这两种方式其实就是通过set方法注入依赖,只是向容器中添加bean的方式不同。

第十节(拓展):自定义组件实现xxxAware接口,使用spring底层的一些组件

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MyAware implements ApplicationContextAware,BeanFactoryAware {

	private ApplicationContext applicationContext; //设置成员变量

	private BeanFactory beanFactory;  //设置成员变量
	
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext; //赋值
	}

	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;  //赋值
		
	}
	
	public void test(){
		//使用 applicationContext、beanFactory
		
	}
}

猜你喜欢

转载自blog.csdn.net/qq_37936542/article/details/82224399