Spring IOC容器
我们创建一个maven工程,并且将spring核心组件依赖到pom文件中,这里使用4.3.12版本,需要其他版本请到maven库中找
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> |
IOC组件注册
@Configuration & @Bean 给容器中注册组件
传统方式
- 编写一个javabean
public class Person {
private String name;
private Integer age;
public person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String toString() {
return "person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public person() {
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
} - 创建一个beans.xml
<bean id="person" class="beans.Person">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean> - 引入beans.xml,创建容器
public class MainClass {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
} - 从容器中拿到bean
/**
* 得到输出结果
* person{name='zhangsan', age=18}
/注解方式
- 我们创建一个配置文件类,并标记注解
@Configuration
- 我们创建一个方法,方法返回值为一个bean,方法上配置
@Bean
Bean的类型为返回值的类型,id默认为方法名作为id。//配置类等同于配置文件
//告诉Spring这是一个配置类
public class MainConfig {
//给容器中注册一个bean
public Person GetPerson()
{
return new Person("lisi",20);
}
} - 使用注解后的容器输出是方法名,如果不想用方法名的话,可以使用
public class MainClass {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = (Person) applicationContext.getBean(Person.class);
System.out.println(person);
String[] names = applicationContext.getBeanNamesForType(Person.class);
for (String name: names) {
System.out.println(name); //输出的是方法名
}
}
}
/**
* 输出
* Person{name='lisi', age=20}
* GetPerson
* /@Bean(value = "person")
指定注入容器中的Bean的名字。
@ComponentScan-自动扫描组件&指定扫描规则
xml方式
<!--包扫描,只要标注了@Controller、@Service、@Repository、@Component,都会被扫描到容器里面--> |
注解方式
在原有的配置类上加@ComponentScan
注解
//配置类等同于配置文件 |
我们可以编写一个dao,一个service,一个controller测试一下。
|
自己注册的类都扫描到了容器中
@ComponentScan
利用excludeFilters
可以指定排除规则,能够根据filter排除掉一些组件不加入容器"com.zenshin",excludeFilters = { (value =
.class, Service.class}) .Filter(type = FilterType.ANNOTATION,classes = {Controller
})这样就排除掉了Controller和Service两个注解标注的类,被这俩注解标注的bean不会加入到容器中。
@ComponentScan
利用includeFilters
可以指定哪些bean加入到容器中"com.zenshin",includeFilters = { (value =
.class, Service.class}) .Filter(type = FilterType.ANNOTATION,classes = {Controller
},useDefaultFilters = false)想要使用
includeFilters
就必须把useDefaultFilters
置为false,这样才会生效。@ComponentScans
可以指定多个ComponentScan
(value = {
"com.zenshin",includeFilters = { (value =
.class, Service.class}), .Filter(type = FilterType.ANNOTATION,classes = {Controller
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
},useDefaultFilters = false)
})FilterType类型
- FilterType.ANNOTATION : 按照注解方式
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
- FilterType.ASSIGNABLE_TYPE : 按照给定的类型
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class})
- FilterType.ASPECTJ : 使用ASPECTJ表达式,基本上用不到
- FilterType.REGEX : 使用正则表达式
- FilterType.CUSTOM : 使用自定义拦截器
- FilterType.ANNOTATION : 按照注解方式
使用自定义拦截器步骤
- 需要实现
TypeFilter
接口public class MyTypeFiler implements TypeFilter {
/**
* metadataReader:当前正在扫描的类的信息
* metadataReaderFactory:可以获取其他任何类的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotatedTypeMetadata annotatedTypeMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类的资源信息(类路径等等)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
return false;
}
}
- 使用只需要在扫描类的时候指定一下拦截规则即可
"com.zenshin",includeFilters = { (value =
.class) .Filter(type = FilterType.CUSTOM,classes = MyTypeFiler
},useDefaultFilters = false)
- 需要实现
@Scope设置组件的作用域
xml方式
<!--scope="prototype" bean创建的作用域--> |
注解方式
/** |
Scope有四种作用域:
- prototype:基于原型模式,每次从容器拿的时候都会创建一个实例
- singleton: 单例的,全局只会有一个实例,默认值
- request: 在web中每一次请求创建一个实例
- session: 在web中同一个session有一个实例
在单实例的情况下,IOC容器启动的会调用方法创建对象放到IOC容器中,以后每次获取就是直接从容器中拿。
在多实例情况下,IOC容器启动的时候并不会调用方法创建对象,放到ioc容器中,以后每次获取的时候才会调用方法创建对象。
@Lazy-bean 懒加载
单实例bean,默认在容器启动的时候创建对象,我们可以对其进行懒加载,容器启动的时候不会创建对象,第一次获取(使用)Bean的时候,才会创建对象并初始化
"person")//默认都是单实例的 ( |
@Conditional-按照条件注册bean
@Conditional:按照一定的条件进行判断,满足条件给容器中注册bean
- 首先我们创建两个bean来注入到容器中如果我们想根据系统类型来注册容器
/**
* @Conditional(): 按照一定的条件进行判断,满足条件给容器中注册bean
*/
"bill") (
public Person person01()
{
return new Person("Bill Gates",60);
}
"linus") (
public Person person02()
{
return new Person("linus",48);
}
1、如果是windows,就注册bill
2、如果是linux就注册linus@Conditional
注解里面传的是一个Condition
数组,Condition
是一个接口,我们需要自己去实现然后在注册bean的地方加上注解即可//创建一个windowsCondition
/**
* 判断是不是windos系统
*/
public class WindowsCondition implements Condition {
/**
*
* @param context 判断条件能使用到的上下文(环境)
* @param metadata 注释信息
* @return
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1、能获取到ioc使用的bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前环境的信息
Environment environment = context.getEnvironment();
//4、获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
//我们需要environment来判断当前操作系统、
String environmentProperty = environment.getProperty("os.name");
if(environmentProperty.contains("Windows"))
{
return true;
}
return false;
}
}
//创建一个linuxCondition
public class LinuxCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Linux"))
{
return true;
}
return false;
}
}这样在windows下就会注册billbean,在linux下就会注册linusbean。/**
* @Conditional(): 按照一定的条件进行判断,满足条件给容器中注册bean
*/
.class}) ({WindowsCondition
@Bean("bill")
public Person person01()
{
return new Person("Bill Gates",60);
}
.class}) ({LinuxCondition
@Bean("linus")
public Person person02()
{
return new Person("linus",48);
}Condition
中可以做很多的判断,包括通过BeanDefinitionRegistry
判断是否注册了什么Bean等功能。@Condition
可以放在方法上,也可以放在类上,放在类上,只有条件为true的时候整个类才会生效,包括类里面注册的bean。
@Import-给容器中快速导入一个组件
首先我们创建一个类,随便一个类不加任何注解
public class Color { |
我们需要在配置类头加一个Import注解,就可以将这个类导入到容器中
|
Import支持数据,可以导入多个组件,id默认组件全类名
@Import中使用importSelector
importSelector
是一个接口,接口中有方法,用于返回需要注册的类,是一个字符串数组,也就是说可以注册很多的类IOC容器中。
- 首先我们需要编写一个类实现
importSelector
接口然后用Import注解用一下这个类即可//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
//返回值就是导入到容器中的组件全类名
//AnnotationMetadata:当前标注@Import注解类的所有注解信息
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//方法不要返回null
return new String[]{"com.zenshin.beans.Color","com.zenshin.beans.Person"};
}
}.class) (MyImportSelector
@Import-使用ImportBeanDefinitionRegistrar
这个也是一个接口,使用方法与importSelector
相同 - 首先我们创建一个类实现
ImportBeanDefinitionRegistrar
依然是利用Import实现public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata 当前类的信息
* @param registry BeanDefinition注册类
* 把所有需要添加到容器的bean,调用BeanDefinitionRegistry.registerBeanDefinition手动注册进来
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean color = registry.containsBeanDefinition("Color");
if(!color)
{
//指定bean名,实现BeanDefinition接口的类
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Color.class);
registry.registerBeanDefinition("Color", rootBeanDefinition);
}
}
}.class) (MyImportBeanDefinitionRegistrar
使用FactoryBean注册组件
FactoryBean
是一个接口,实现这个接口后,有三个方法,getObject()
返回的对象会直接添加到容器中,一般用于创建比较复杂的Bean
public class ColorFactoryBean implements FactoryBean { |
还需要将ColorFactoryBean放到容器中,
|
这样就把Color
对象放到了容器中,但是容器中的id是colorFactoryBean
。
我们来获取一下试试
|
- applicationContext.getBean(“colorFactoryBean”):获取的是Color对象
- applicationContext.getBean(“&colorFactoryBean”):获取的是ColorFactoryBean对象
默认创建的是工厂bean调用getObject创建的对象,需要获取工厂bean本身,我们需要在id前面加一个&。
注册方法总结
给容器中注册组件:
1、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[我们自己写的类]
2、@Bean 导入第三方包里面的注解
3、@Import 快速给容器中导入一个组件
4、使用Spring提供的FeactoryBean(工厂Bean)
Bean的生命周期
Bean的生命周期指的是:bean创建—初始化—销毁的过程。
初始化: 对象创建完成,并赋值好,调用初始化方法(多实例是获取的时候,单实例是容器创建的时候)
销毁:容器关闭的时候执行(多实例容器不会管理这个bean。容器不会调用销毁方法,只能我们手动去调用)
现在容器管理bean的生命周期,我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
- 指定初始化和销毁方法自定义
- 使用@Bean指定
initMethod
和destroyMethod
方法
- 使用@Bean指定
- 通过让Bean实现接口
InitializingBean
和DisposableBean
。 - 使用jsr250的两个注解@PostConstruct和@PreDestroy
- 实现
BeanPostProcessor
接口,作为Bean的后置处理器@Bean-指定初始化和销毁方法
在xml中我们可以用init-method
和destroy-method
指定初始化和销毁方法。用注解的方法<bean id="person" class="com.zenshin.beans.Person" scope="prototype" init-method="指定方法" destroy-method="指定方法">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean> - 如果我们创建一个Car类,编写无参构造函数,以及init(),destory()方法
public class Car {
public Car()
{
System.out.println("Car constructor...");
}
public void init()
{
System.out.println("car....init....");
}
public void destroy()
{
System.out.println("car.....destory....");
}
} - 然后加入到容器中去
public class MainConfigOfLifeCycle {
"init",destroyMethod = "destroy") //加入容器中的时候指定初始化和销毁方法 (initMethod =
public Car car()
{
return new Car();
}
} - 初始化容器,然后打印输出信息
public void test01()
{
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
applicationContext.close();//容器关闭
}
//输出信息为
//Car constructor...
//car....init....
//容器创建完成
//car.....destory.... - 这个时候就会调用Car类的初始化和销毁方法。
InitializingBean和DisposableBean
通过继承InitializingBean
和DisposableBean
,实现afterPropertiesSet
和destroy
方法
public class Cat implements InitializingBean, DisposableBean { |
然后加入到容器中,加入到容器中以后,我们初始化容器,就能看到打印的消息了。
@PostConstruct和@PreDestroy
这两个注解是JSR250规范中的注解,
@PostConstruct
:在bean创建完成并且属性赋值完成以后,来执行初始化方法@PreDestroy
:在bean将要被移除之前通知@PreDestroy,进行调用。我们将Dog加入到容器中测试一下public class Dog {
public Dog() {
System.out.println("Dog constructor...");
}
//对象创建并赋值之后调用
public void init()
{
System.out.println("Dog ...PostConstruct");
}
//容器移除对象之前
public void destroy()
{
System.out.println("Dog...destroy");
}
}
public void test02()
{
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
Dog dog = applicationContext.getBean(Dog.class);//Dog constructor... Dog ...PostConstruct
applicationContext.removeBeanDefinition("dog");//Dog...destroy
}
BeanPostProcessor-后置处理器
在bean初始化前后,进行一些处理工作
postProcessBeforeInitialization
在初始化之前进行工作。postProcessAfterInitialization
在初始化之后进行工作。在初始化之前和之后就是调用这俩个方法。/**
* 后置处理器,初始化前后进行处理工作
* 将后置处理器加入到容器中
*/
public class MyBeanPostProessor implements BeanPostProcessor {
/**
* @param bean 创建的bean实例
* @param beanName bean的名字
* @return 返回值就是bean实例
* @throws BeansException
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization...."+beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization,...."+beanName);
return bean;
}
}
这个的实现类似于一个切面,就是在调用初始化方法的前后调用这两个方法applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);指定初始化方法之前protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //前
}
try {
invokeInitMethods(beanName, wrappedBean, mbd); //初始化方法
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); //后
}
return wrappedBean;
}
获取所有的后置处理器,依次执行,一旦有返回null的处理器就不会执行后面的处理器了。
invokeInitMethods(beanName, wrappedBean, mbd)执行初始化方法,
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 初始化方法之后
初始化方法之前,调用populateBean(beanName, mbd, instanceWrapper);
给bean属性进行赋值。赋值完以后在执行initializeBean(beanName, exposedObject, mbd);
Spring底层对BeanPostProcessor的应用
我们可以找到BeanPostProcessor
接口,然后找到他的实现类,这里举例ApplicationContextAwareProcessor
//这是他的postProcessBeforeInitialization方法 |
这里可以看到,postProcessBeforeInitialization
调用了invokeAwareInterfaces
方法,这里面有一个ApplicationContextAware
接口,这个接口有一个setApplicationContext
方法,这个方法把IOC容器注入到了bean中,所以我们可以得出,如果我们想要在bean中加入ioc容器,我们可以实现ApplicationContextAware
接口然后可以实现setApplicationContext
方法得到IOC容器。
|
这种装配只能是在初始化之前无感的注入,不然初始化完毕自己的bean再注入那就不叫初始化了,哈哈哈。
Spring底层还有很多地方用到了这个方式,包括自动注入也是利用这种方式去注入的。
属性赋值
我们定义的bean中有属性,属性如何获取呢我们在xml中可以使用value去赋值,那么同样注解版也是有@Value可以对属性进行赋值的。
@Value赋值
1、基本数值
2、可以写SpEL,#{}
3、可以${},取出配置文件中的值(在运行环境变量里面的值)
public class Person { |
@PropertySource加载外部配置文件
- 使用xml的方式
<!--使用context来将配置文件放到beans.xml中,然后${}调用-->
<context:property-placeholder location="person.properties"/>
<bean id="person" class="com.zenshin.beans.Person" scope="prototype">
<property name="name" value="${person.name}"></property>
<property name="age" value="18"></property>
</bean> - 使用
@PropertySource
注解- 在配置类中加入如下注解
//使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中
"classpath:/person.properties"})//配置文件的路径 (value = {
public class MainConfigOfPropertyValues {
public Person person()
{
return new Person();
}
} - 在需要的地方使用${}取出配置
"${person.Nickname}") (
private String NickName; - 配置文件中的值都加载到了环境变量中,我们可以从环境变量中取出来
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getProperty("person.Nickname")); //从环境变量中获取值
- 在配置类中加入如下注解
这样就可以获取到配置文件中的信息了。
自动装配
Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值;
1、使用@Autowired注解实现注入
2、使用XXXAware来获取Spring底层的注入类
@Autowired & @Qualifier & @Primary
|
- 默认优先按照类型到容器中找对应的组件,如果找到就进行赋值
- 如果该类型的组件在容器中有多个,再将属性的名称作为组件的id去容器中查找
- 我们可以使用
@Qualifier("bookDao")
明确指定注入的是哪个对象,根据id获取,而不是使用属性名 Autowired
自动装配默认一定要将属性赋值好,如果容器中没有这个组件,那么注入的时候就会报错,@Autowired
有一个属性required
是否必须,默认是true,改为false可以不报错也获取不到注入的对象。@Primary
:让Spring进行自动装配的时候默认使用首选的bean。这个注解是放在bean上的,如果有bean加上了这个注解,那么在自动装配的时候就会首选这个bean
@Resource & @Inject
@Resource
是JSR250规范中的注解,@Inject
是JSR330规范的注解,这两个都是java规范的注解
@Resource注解使用
public class BookService {
"bookDao") (name=
BookDao bookDao;
public void test()
{
bookDao.test();
}
}Resource可以和Autowired一样能实现自动装配功能,默认是组件名称进行装配的,也可以使用name属性指定注入的对象,不支持
@Primary
功能也不支持@Autowired(required = false)
功能@Inject注解使用
这个注解的使用需要导入一个依赖<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>使用方法与Autowried注解使用方式一样,但是没有
required
属性@Resource与@inject都是java规范,脱离了spring依旧可以使用其他框架支持,但是@Autowired是Spring的框架中的注解,是脱离Spring就不支持了
自动装配功能的实现是通过AutowiredAnnotationBeanPostProcessor
后置处理器去解析注解然后自动装配的。
方法、构造器位置的自动装配
@Autowired
注解不只是能标注在属性上,还能标注在构造器,参数,方法上
- 标注在set方法上
public class BookService {
public BookDao getBookDao() {
return bookDao;
}
//标注在方法上面,Spring容器创建当前对象,就会调用方法去赋值
//方法使用的参数,自定义类型的值从ioc容器中进行获取。
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
private BookDao bookDao;
public void test()
{
bookDao.test();
}
} - 标注在构造器上实现构造器注入
在IOC容器中,我们默认加到IOC容器中欸得组件,容器启动的时候会调用无参构造器创建对象,再进行初始化赋值等操作。
当@Autowired
标注以后,IOC容器就会在实例化得时候将构造器中用到得类注入进去。如果组件有且只有一个有参构造器,这个有参构造器的@Autowired
可以省略。
public class BookService {
public BookService(BookDao bookDao) {
this.bookDao = bookDao;
}
private BookDao bookDao;
public void test()
{
bookDao.test();
}
} @Autowired
也可以放在参数位置,也是从容器中获取
public class BookService {
public void test(@Autowired BookDao bookDao)
{
bookDao.test();
}
}@Bean
标注的方法在创建对象的时候,方法参数的值也是从容器中取得。
自定义组件使用Spring底层组件
如:ApplicationContext,BeanFactory
自定义组件使用这些得时候,只需要实现 XXXAware接口实现方法即可,在创建对象的时候,会调用接口规定的方法注入相关组件;
使用方式在BeanPostProcessor Spring底层应用
讲到过。
|
EmbeddedValueResolverAware
能够处理字符串里面的数值,解析成正确的字符串,这样输出为:你好Windows 10 我是60
XXXAware是通过XXXProcessor来处理的,一一对应。
@Profile环境搭配
@Profile:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能。
因为我们在开发过程中往往会有开发环境,测试环境和生产环境,需要在这三个里面进行切换,所以需要@Progile注解来实现。
@Profile
:指定组件在哪个环境的情况下才能被注册到容器中,不指定在任何环境下都能注册这个组件
- 加了环境表示的bean,只有这个环境被激活的时候才会注册到容器中
- 注解也可以加到整个类上面,效果是一样的,也是当环境一致的时候我们的类才能生效。如果加到整个配置类上,只有指定环境的时候,整个配置类里面的配置才能生效。
- 没有标注环境表示的bean在任何环境下都是加载的。
@Profile("default")
是默认环境。- @Profile直接标记在需要添加的Bean上面即可我们现在运行容器会发现什么都没有加进入。
public class MainConfigOfProfile {
"test") (
"testDataSource") (
public DataSource dataSourceTest() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setJdbcUrl("jdbc:mysql://192.163.1.8:3306/test");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return dataSource;
}
"dev") (
"devDataSource") (
public DataSource dataSourceDev() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setJdbcUrl("jdbc:mysql://192.163.1.8:3306/dev");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return dataSource;
}
"pro") (
"proDataSource") (
public DataSource dataSourcePro() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setJdbcUrl("jdbc:mysql://192.163.1.8:3306/pro");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
return dataSource;
}
}
//定义了三个数据源,分别对应三个环境,@Profile()就标注在bean上面 - 如何定义环境,使得 @Profile注解能够生效
- 使用命令行动态参数:在vm的参数里面添加
-Dspring.profiles.active=test
指定运行环境 - 使用代码的方式,其实就是将applicationContext的创建过程增加了一个设置环境的步骤。
public void test01()
{
//1、创建一个applicationContext,使用无参构造器,有参构造器来不及设置就直接创建容器了
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//2、设置需要激活的环境
applicationContext.getEnvironment().addActiveProfile("test");
//3、注册主配置类
applicationContext.register(MainConfigOfProfile.class);
//4、启动刷新容器
applicationContext.refresh();
String[] names = applicationContext.getBeanDefinitionNames();
for (String name:names) {
System.out.println(name);
}
}
- 使用命令行动态参数:在vm的参数里面添加
IOC小结
Spring最主要的就是容器,在IOC容器这一章主要讲的是组件的添加、组件的赋值、组件的注入
我们来看一下图,看一下这里面有哪些主要内容
这就是本篇文章的全部内容,IOC容器中还有AOP和声明式事务,这个在后面进行讲解。
这里仅仅算一个概览,更多的参照一下Spring的官方文档