Spring注解驱动开发-属性赋值&自动装配(三)

关联文章:

Spring注解驱动开发-组件注册(一)

Spring注解驱动开发-生命周期(二)

Spring注解驱动开发-属性赋值&自动装配(三)

Spring注解驱动开发-AOP(四)

@Value属性赋值


  • 基本数值
  • 可以写SpEL,#{}
  • 可以写${},取出配置文件中的值 (在运行环境变量里面的值
@Data@AllArgsConstructor@NoArgsConstructor
public class Person {
	
	@Value("小红")         //第一种方式赋值
	private String name;
	@Value("#{20-2}")       //第二种方式
	private int age;
	@Value("${person.nickNamee}")   //第三种方式
	private String nickName;
}

配置类:

使用@PropertySource读取外部配置文件中的k/v保存到运行环境变量中
加载完外部配置文件后就可以用${}取值

//使用@PropertySource读取外部配置文件中的k/v保存到运行环境变量中
//加载完外部配置文件后就可以用${}取值
@PropertySource(value = { "classpath:person.properties" })//可以写多个配置文件
@Configuration//这是一个配置类==配置文件
public class ManConfigOfProperty {
	@Bean
	public Person person() {
		return new Person();
	}
	
}

测试

	@Test
	public void test1() throws Exception {
		//1.创建IOC容器
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ManConfigOfProperty.class);
		System.out.println("容器创建完成...");
		Person bean = ac.getBean(Person.class);
		System.out.println(bean);
		System.out.println("=====================");
		ConfigurableEnvironment environment = ac.getEnvironment();
		String property = environment.getProperty("person.nickNamee");
		System.out.println(property);
		
	}
}

结果

容器创建完成...
Person(name=小红, age=18, nickName=小张三)
=====================
小张三

自动装配:spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值


1.@Autowired 自动注入[Spring定义的]


  1. 默认优先ByType(按照类型)去容器中找对应的组件:applocationContext.getBean(EmployeeService.class);
  2. 如果找到多个相同类型的组件, 再将属性的名称作为组件的id去容器中查
  3. 使用@Qualifier明确指定需要装配组件的id  @Qualifier("employeeService2"):
  4. 自动装配一定要将属性赋值好,没有就会报错(IOC容器要有要赋值的组件,不然异常)                                                     可以使用@Autowired(required=false)
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.zxc.service.EmployeeService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: 

  5.@Primary:让Spring进行自动装配的时候,默认使用首选bean,也可以继续使用@Qualifier指定要装配的bean名字


service:

@Service
@Getter@Setter
public class EmployeeService {
	private int label = 1;
	@Override
	public String toString() {
		return "EmployeeService [label=" + label + "]";
	}
}

controller:

@Controller
public class EmployeeController {
	@Qualifier("employeeService2")
	@Autowired
	private EmployeeService employeeService;

	@Override
	public String toString() {
		return "EmployeeController [employeeService=" + employeeService + "]";
	}
}

配置类:

@Configuration
@ComponentScan({"com.zxc.service","com.zxc.controller"})
public class MainConfigOfAutowired {
	
	@Bean("employeeService2")
	public EmployeeService employeeService() {
		EmployeeService employeeService = new EmployeeService();
		employeeService.setLabel(2);
		return employeeService;
	}
}

测试

@Test
public void test1() throws Exception {
	//1.创建IOC容器
	AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
	System.out.println("容器创建完成...");
	EmployeeController bean = (EmployeeController) ac.getBean("employeeController");
	System.out.println(bean);
	Object bean2 = ac.getBean("employeeService");
	System.out.println(bean2);
	
}

输出:

容器创建完成...
//使用了@Qualifier指定了注入的对象
EmployeeController [employeeService=EmployeeService [label=2]]
EmployeeService [label=1]

2.@Resource(JSR250)和 @Inject(JSR330)[java规范的注解]


@Resource:

     和@Autowired一样实现自动装配,默认按照组件名称进行装配。没有支持@Primary和@Autowired(required=false)功能

@Inject:

     需要导入javax.inject的包,和@Autowired功能一样,没有required=false的功能  

AutowiredAnnotationBeanPostProcessor :解析完成自动装配功能

3.@Autowired贴在:构造器,参数,方法,属性都是从容器中自动获取组件


1).标注在构造器上  如果组件只有一个有参构造器,@Autowired可以省略,参数位置的组件可以自动注入

2).标注在方法上  直接标注在set方法上或者@Bean+方法参数,参数从容器自动注入(默认不写,也可以自动装配)

3).标注在参数上

4.自动装配Spring底层组件(实现xxxAware接口)


自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory)

自定义组件实现xxxAware,在创建对象的时候会调用接口规定的方法注入相关的组件

xxxAware:功能使用xxxProcessor  比如ApplicationContextAware==>ApplicationContextAwareProcessor(后置处理器)

实现几个常见的Aware接口:

public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware{

	@Override  //Embedded 植入的,深入的,内含的
	public void setEmbeddedValueResolver(StringValueResolver stringvalueresolver) {
		String stringValue = stringvalueresolver.resolveStringValue("解析字符串"+"${os.name} "+"#{10*10}");
		System.out.println(stringValue);
	}

	@Override
	public void setBeanName(String s) {
		System.out.println("当前Bean的名字:"+s);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationcontext) throws BeansException {
		System.out.println("传入的IOC:"+applicationcontext);
	}

}

注入到Ioc容器后测试结果:

当前Bean的名字:com.zxc.bean.Red
解析字符串Windows 10 100
传入的IOC:org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: startup date [Mon Mar 04 20:16:52 CST 2019]; root of context hierarchy

原理:

Debug定位到ApplicationContextAwareProcessor.postProcessBeforeInitialization()方法

    public Object postProcessBeforeInitialization(final Object bean, String beanName)
        throws BeansException
    {
        AccessControlContext acc = null;
        if(System.getSecurityManager() != null && ((bean instanceof EnvironmentAware) || (bean instanceof EmbeddedValueResolverAware) || (bean instanceof ResourceLoaderAware) || (bean instanceof ApplicationEventPublisherAware) || (bean instanceof MessageSourceAware) || (bean instanceof ApplicationContextAware)))
            acc = applicationContext.getBeanFactory().getAccessControlContext();
        if(acc != null)
            AccessController.doPrivileged(new PrivilegedAction() {

                public Object run()
                {
                    invokeAwareInterfaces(bean);
                    return null;
                }

                final Object val$bean;
                final ApplicationContextAwareProcessor this$0;

            
            {
                this.this$0 = ApplicationContextAwareProcessor.this;
                bean = obj;
                super();
            }
            }, acc);
        else
            invokeAwareInterfaces(bean);
        return bean;
    }

调用下面方法进行判断

   private void invokeAwareInterfaces(Object bean)
    {
        if(bean instanceof Aware)
        {
            if(bean instanceof EnvironmentAware)
                ((EnvironmentAware)bean).setEnvironment(applicationContext.getEnvironment());
            if(bean instanceof EmbeddedValueResolverAware)
                ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(embeddedValueResolver);
            if(bean instanceof ResourceLoaderAware)
                ((ResourceLoaderAware)bean).setResourceLoader(applicationContext);
            if(bean instanceof ApplicationEventPublisherAware)
                ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(applicationContext);
            if(bean instanceof MessageSourceAware)
                ((MessageSourceAware)bean).setMessageSource(applicationContext);
            if(bean instanceof ApplicationContextAware)
                ((ApplicationContextAware)bean).setApplicationContext(applicationContext);
        }
    }

5.自动装配@Profile环境搭建


profile:侧面,半面; 外形,轮廓 

Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能

  • 贴了@Profile的bean,只有这个环境被激活才能注册到容器。默认是default环境
  • 没贴,任何环境都可以注册这个bean
  • 贴在配置类上,只有是指定环境的时候,整个配置类里面的所有配置才能生效

二种方式指定(激活)环境:

  •  使用命令动态参数激活:虚拟机参数位子加载 -Dspring.profiles.active=test
  •  使用代码激活环境

例子:

开发环境,测试环境,生产环境

数据源:(/A)(/B)(/C)

配置类:

@Configuration // 配置类==配置文件
public class MainConfig_Profile implements EmbeddedValueResolverAware {

	@Value("${jdbc.username}")
	private String userName;
	private String url;

	@Profile("test")
	@Bean("testDateSource")
	public DataSource DataSourceTest(@Value("${jdbc.password}") String password) {
		DruidDataSource ds = new DruidDataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl(url);
		ds.setPassword(password);
		ds.setUsername(userName);
		return ds;
	}

	@Profile("dev")
	@Bean("devDateSource")
	public DataSource DataSourceDevelopMent(@Value("${jdbc.password}") String password) {
		DruidDataSource ds = new DruidDataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl(url);
		ds.setPassword(password);
		ds.setUsername(userName);
		return ds;
	}

	@Override // Embedded 植入的,深入的,内含的
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		String resolveStringValue = resolver.resolveStringValue("${jdbc.url}");
		this.url = resolveStringValue;
	}
}

测试:

注意 :使用无参构造器创建一个applicationContext,我们设置环境后自己注册配置类,有参就走下面流程了

public AnnotationConfigApplicationContext(Class... annotatedClasses) {
		this();
		register(annotatedClasses);  //注册配置类
		refresh();
	}
@Test
public void test1() throws Exception {
	// 1.使用无参构造器创建一个applicationContext
	AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
	// 2.设置需要激活的环境
	ac.getEnvironment().setActiveProfiles("test");
	// 3.注册配置类
	ac.register(MainConfig_Profile.class);
	// 4. 启动刷新容器
	ac.refresh();
	// 获取容器中的bean名称打印
	String[] definitionNames = ac.getBeanDefinitionNames();
	for (String string : definitionNames) {
		System.out.println(string);
	}
}

输出:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig_Profile
testDateSource

 

你可能感兴趣的:(Spring)