一、使用 maven 建立一个 java 项目,依赖以下:java
<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.11</version> <scope>test</scope> </dependency>
二、建立测试 pojo:linux
package com.springanno.pojo; public class User { public User() { } public User(String name, Integer age) { 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; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
@Configuration 标注的类就是一个 Spring 配置类,配置类的做用就至关于以前咱们使用的 Spring 配置文件。web
一、建立配置类,经过 @Configuration 注解标注一个类为配置类:spring
package com.springanno.config; import org.springframework.context.annotation.Configuration; /** * 配置类 */ @Configuration public class MainConfig { }
二、经过读取注解配置类来建立 IOC 容器:windows
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
@ComponentScan 注解的做用至关于在 Spring 配置文件中配置 <context:component-scan> 标签。数组
一、建立测试 Service 类:session
package com.springanno.service; import org.springframework.stereotype.Service; @Service public class UserService { }
二、使用 @ComponentScan 注解:app
package com.springanno.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** * 配置类 */ @Configuration @ComponentScan("com.springanno") public class MainConfig { }
三、测试:maven
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); UserService bean = applicationContext.getBean(UserService.class); System.out.println(bean); /* com.springanno.service.UserService@77e9807f */
@ComponentScan 相关属性:ide
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}, // 不扫描指定注解标注的类
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class})}, // 仅扫描指定注解标注的类 useDefaultFilters = false
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class}), // 过滤指定注解标注的类 @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserService.class}), // 过滤给定类型的类 @ComponentScan.Filter(type = FilterType.ASPECTJ,pattern = {"com.springanno.service.*Service"}), // 经过 ASPECTJ 表达式过滤指定类 @ComponentScan.Filter(type = FilterType.REGEX, pattern ={".*.*Service"}), // 经过正则过滤指定类
还可自定义过滤规则,先自定义一个 TypeFilter 类:
package com.springanno.config; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; public class MyTypeFilter implements TypeFilter { /** * @param metadataReader 正在扫描的类的信息 * @param metadataReaderFactory 可获取其它类信息 * @return 若是返回 true ,说明当前扫描的类匹配成功 */ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 获取当前类注解信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); // 获取当前正在扫描的类的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 获取当前类资源 Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("--->"+className); return true; } }
使用以下:
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) // 自定义规则过滤
@Bean 注解的做用至关于在 Spring 配置文件中配置 <bean> 标签。
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MainConfig { /** * 默认状况下方法名为 bean 的 id * 返回值为加入到 IOC 容器的实例 * 可经过 @Bean 注解的 value 属性指定 bean 的 id * * <bean id="user1" class="com.springanno.pojo.User"> * <property name="name" value="张三"/> * <property name="age" value="20"/> * </bean> */ @Bean(value = "user1") public User user(){ return new User("张三", 20); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Object user1 = applicationContext.getBean("user1"); System.out.println(user1); /* User{name='张三', age=20} */
还能够经过 FactoryBean 方式注册:
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.beans.factory.FactoryBean; public class UserFactoryBean implements FactoryBean<User> { /** * 返回的对象将会添加到容器 */ public User getObject() throws Exception { return new User("ice",22); } /** * 对象类型 */ public Class<?> getObjectType() { return User.class; } /** * 是否单例 */ public boolean isSingleton() { return true; } }
package com.springanno.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MainConfig { @Bean public UserFactoryBean userFactoryBean(){ return new UserFactoryBean(); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } Object user = applicationContext.getBean("userFactoryBean"); System.out.println(user); /* mainConfig userFactoryBean User{name='ice', age=22} */ // 能够看到,咱们获取的是 userFactoryBean,但实际上返回的是 userFactoryBean 对应实例的 getObject 方法的返回值 // 若是咱们的确要获取 userFactoryBean 对应的实例,可经过 &id 这种方式获取: UserFactoryBean userFactoryBean = (UserFactoryBean) applicationContext.getBean("&userFactoryBean"); System.out.println(userFactoryBean); /* com.springanno.config.UserFactoryBean@4461c7e3 */
@Scope 注解做用至关于在 <bean> 标签上的 scope 属性。
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration public class MainConfig { /** * @Scope * value 属性有以下可选值: * singleton(默认): 单例。IOC 容器启动时就会调用方法建立对象放到容器,以后每次使用都是直接从容器中取。 * prototype : 多例。只有要使用该对象时才会调用该方法建立对象。 * request (web 环境): 一次请求。 * session (web 环境): 一次会话。 */ @Scope("prototype") @Bean public User user(){ return new User("张三", 20); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Object user1 = applicationContext.getBean("user"); Object user2 = applicationContext.getBean("user"); System.out.println(user1==user2); /* false */
@Lazy 注解做用至关于在 <bean> 标签上配置属性 lazy-init="true" 。
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; @Configuration public class MainConfig { /** * 懒加载:针对单实例 bean,控制容器启动时不建立对象,第一次获取该 bean 时才建立对象。 */ @Lazy @Bean public User user(){ System.out.println("建立了"); return new User("张三", 20); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); /* [无任何输出] */
按照指定的条件进行判断,知足条件才在容器中注册 bean。
有以下示例,若是当前操做系统为 Windows 时,咱们注册一个 id 为 windows 的 bean,当前系统为 Linux 时,注册一个 id 为 linux 的 bean。
一、建立 Condition 类:
package com.springanno.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; /** * 判断是不是 Windows 系统 */ public class WindowsCondition implements Condition { public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { Environment environment = conditionContext.getEnvironment(); String osName = environment.getProperty("os.name").toLowerCase(); return osName.contains("windows"); } }
package com.springanno.condition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; /** * 判断是不是 Linux 系统 */ public class LinuxCondition implements Condition { /** * @param conditionContext 判断条件能使用的上下文 * @param annotatedTypeMetadata 注解信息 */ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { // 获取到容器使用的 BeanFactory ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory(); // 获取类加载器 ClassLoader classLoader = conditionContext.getClassLoader(); // 获取当前环境信息 Environment environment = conditionContext.getEnvironment(); // 获取 bean 定义的注册类 BeanDefinitionRegistry registry = conditionContext.getRegistry(); String osName = environment.getProperty("os.name").toLowerCase(); return osName.contains("linux"); } }
二、使用:
package com.springanno.config; import com.springanno.condition.LinuxCondition; import com.springanno.condition.WindowsCondition; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class MainConfig { @Conditional({WindowsCondition.class}) @Bean public User windows() { return new User("windows", 20); } @Conditional({LinuxCondition.class}) @Bean public User linux() { return new User("linux", 3); } }
三、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { System.out.println(beanName); } /* mainConfig windows */ // 当前是在 windows 下,因此能够看到只注册了 windows bean
@Import 提供了下面几种注册 bean 到容器的方式。
能够直接将指定 bean 实例注册到容器:
@Configuration /** * @Import 能够直接将注册指定 bean 到容器中,id 为 bean 的类全路径名 */ @Import({User.class}) public class MainConfig { }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } /* mainConfig com.springanno.pojo.User */
经过 @ImportSelector 返回 bean 的全路径数组批量注册:
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.List; public class MyImportSelector implements ImportSelector { public String[] selectImports(AnnotationMetadata annotationMetadata) { List<String> classNameList = new ArrayList<String>(); classNameList.add(User.class.getName()); return StringUtils.toStringArray(classNameList); } }
package com.springanno.config; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration /** * MyImportSelector.selectImports() 方法返回的类的全路径列表, * @Import 将会把这些全路径对应的类都注册到容器,id 为类的全路径名 */ @Import({MyImportSelector.class}) public class MainConfig { }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } /* mainConfig com.springanno.pojo.User */
经过 @ImportBeanDefinitionRegistrar 手动定义 bean 的信息完成 bean 的注册:
package com.springanno.config; import com.springanno.pojo.User; 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; public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * * @param annotationMetadata 当前类注解信息 * @param beanDefinitionRegistry BeanDefinition 注册类 * */ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { // 判断 IOC 容器中是否已经注册了 user boolean isContainsUser = beanDefinitionRegistry.containsBeanDefinition("user"); // 能够经过 beanDefinitionRegistry.registerBeanDefinition() 方法注册全部须要添加到容器中的 bean if(!isContainsUser){ RootBeanDefinition beanDefinition = new RootBeanDefinition(User.class.getName()); // id=user beanDefinitionRegistry.registerBeanDefinition("user", beanDefinition); } } }
package com.springanno.config; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration /** * @Import 会执行 MyImportBeanDefinitionRegistrar.registerBeanDefinitions(),在该方法中完成 bean 的注册 */ @Import({MyImportBeanDefinitionRegistrar.class}) public class MainConfig { }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { System.out.println(beanDefinitionName); } /* mainConfig user */
这里说的生命周期指的是注册进 IoC 容器的 bean 的生命周期,可经过下面几种方式来监听 bean 的生命周期变化。
经过 @Bean 注解的 initMethod 属性来指定 bean 的初始化方法, destroyMethod 属性来指定 bean 的销毁方法。
package com.springanno.pojo; public class User { public User() { } public User(String name, Integer age) { System.out.println("User 构造方法"); 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; } public void init(){ System.out.println("User 初始化方法"); } public void destroy(){ System.out.println("User 销毁方法"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MainConfig { /* 经过 @Bean 注解的 initMethod 属性来指定 bean 的初始化方法,destroyMethod 属性来指定 bean 的销毁方法 构造方法: 单实例 bean 在容器启动的时候执行 多实例 bean 在每次获取 bean 的时候执行 初始化方法: 构造方法执行后执行 销毁方法: 单实例 bean 在容器关闭时执行 多实例时,容器不会管理这个 bean ,因此不会调用销毁方法 */ @Bean(initMethod = "init", destroyMethod = "destroy") public User user(){ return new User("tom", 12); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); ((AnnotationConfigApplicationContext) applicationContext).close(); /* User 构造方法 User 初始化方法 User 销毁方法 */
经过将 @PostConstruct 和 @PreDestroy 注解标注在 bean 的方法上让其成为初始化方法和销毁方法。
package com.springanno.pojo; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class User { public User() { } public User(String name, Integer age) { System.out.println("User 构造方法"); 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; } @PostConstruct public void init() throws Exception { System.out.println("User init"); } @PreDestroy public void destroy() throws Exception { System.out.println("User destroy"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MainConfig { @Bean public User user(){ return new User("tom", 12); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); ((AnnotationConfigApplicationContext) applicationContext).close(); /* User 构造方法 User init User destroy */
经过让 bean 实现 InitializingBean 来定义初始化逻辑,实现 DisposableBean 来定义销毁逻辑。
package com.springanno.pojo; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class User implements InitializingBean, DisposableBean { public User() { } public User(String name, Integer age) { System.out.println("User 构造方法"); 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; } public void afterPropertiesSet() throws Exception { System.out.println("User afterPropertiesSet"); } public void destroy() throws Exception { System.out.println("User destroy"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MainConfig { @Bean public User user(){ return new User("tom", 12); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); ((AnnotationConfigApplicationContext) applicationContext).close(); /* User 构造方法 User afterPropertiesSet User destroy */
定义一个类实现 BeanPostProcessor 接口,将其注册到容器中后它即可以监听容器中全部 bean 的初始化前和初始化后操做。
package com.springanno.config; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; @Component public class MyBeanPostProcessor implements BeanPostProcessor { /** * 初始化操做执行以前执行 */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println(beanName + "---->postProcessBeforeInitialization"); return bean; } /** * 初始化操做执行以后执行 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println(beanName + "---->postProcessAfterInitialization"); return bean; } }
package com.springanno.pojo; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class User { public User() { } public User(String name, Integer age) { System.out.println("User 构造方法"); 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; } @PostConstruct public void init() throws Exception { System.out.println("User init"); } @PreDestroy public void destroy() throws Exception { System.out.println("User destroy"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); ((AnnotationConfigApplicationContext) applicationContext).close(); /* User 构造方法 user---->postProcessBeforeInitialization User init user---->postProcessAfterInitialization User destroy */
Spring 底层给 bean 赋值、@Autowried 注入、生命周期注解等功能都是经过 BeanPostProcessor 完成的。
ScheduledAnnotationBeanPostProcessor (org.springframework.scheduling.annotation)
AdvisorAdapterRegistrationManager (org.springframework.aop.framework.adapter)
BeanPostProcessorChecker in PostProcessorRegistrationDelegate (org.springframework.context.support)
ImportAwareBeanPostProcessor in ConfigurationClassPostProcessor (org.springframework.context.annotation)
LoadTimeWeaverAwareProcessor (org.springframework.context.weaving)
AbstractAdvisingBeanPostProcessor (org.springframework.aop.framework)
AbstractBeanFactoryAwareAdvisingPostProcessor (org.springframework.aop.framework.autoproxy)
DestructionAwareBeanPostProcessor (org.springframework.beans.factory.config)
InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
ApplicationListenerDetector in PostProcessorRegistrationDelegate (org.springframework.context.support)
ApplicationContextAwareProcessor (org.springframework.context.support)
MergedBeanDefinitionPostProcessor (org.springframework.beans.factory.support)
InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
RequiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
ApplicationListenerDetector in PostProcessorRegistrationDelegate (org.springframework.context.support)
BeanValidationPostProcessor (org.springframework.validation.beanvalidation)
InstantiationAwareBeanPostProcessor (org.springframework.beans.factory.config)
SmartInstantiationAwareBeanPostProcessor (org.springframework.beans.factory.config)
CommonAnnotationBeanPostProcessor (org.springframework.context.annotation)
使用 @Value 能够为属性赋基本数值,也能够经过语法 @Value("#{SpEL}") 经过 SpEL 表达式赋值,还能够经过 ${属性名} 取出配置文件(环境变量)中的值,而 @PropertySource 注解就能够帮咱们读取属性文件中的属性到环境变量。
user.testKey=testValue
package com.springanno.pojo; import org.springframework.beans.factory.annotation.Value; public class User { public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } @Value("张三") private String name; @Value("#{19+3}") private Integer age; @Value("${user.testKey}") private String testKey; 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; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", testKey='" + testKey + '\'' + '}'; } }
package com.springanno.config; import com.springanno.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource(value = {"classpath:user.properties"}) // 使用该注解将指定属性文件加载到环境变量 public class MainConfig { @Bean public User user() { return new User(); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); User bean = applicationContext.getBean(User.class); System.out.println(bean); /* User{name='张三', age=22, testKey='testValue'} */
经过使用 @Profile 注解,Spring 能够实现根据当前环境动态的激活和切换一些列组件的功能。
package com.springanno.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @Configuration public class MainConfig { /* 指定环境了的组件只有在指定环境下运行时才会注册到容器中,不指定环境的组件任何环境都能注册到容器中,默认为 default 环境 这里模拟三个环境下的数据源 */ @Profile("dev") @Bean("dataSource") public String devStr(){ return "devDataSource"; } @Profile("test") @Bean("dataSource") public String testStr(){ return "testDataSource"; } @Profile("prod") @Bean("dataSource") public String prodStr(){ return "prodDataSource"; } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Object dataSource = applicationContext.getBean("dataSource"); System.out.println(dataSource); // 经过 VM-options 来指定运行环境 // -Dspring.profiles.active=dev 时,输出 devDataSource // -Dspring.profiles.active=test 时,输出 testDataSource // -Dspring.profiles.active=prod 时,输出 prodDataSource
String profileStr = "test"; AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 指定运行环境 applicationContext.getEnvironment().setActiveProfiles(profileStr); applicationContext.register(MainConfig.class); applicationContext.refresh(); Object dataSource = applicationContext.getBean("dataSource"); System.out.println(dataSource); /* 编码指定运行环境 profileStr="test" 时,输出 testDataSource profileStr="prod" 时,输出 prodDataSource profileStr="dev" 时,输出 devDataSource */
Spring 利用 DI(依赖注入),完成对 IoC 容器中各个组件的依赖赋值。
@Autowired 将会自动从 IoC 容器中查找与标注属性同类型的 bean 注入, 若是容器中有多个相同类型的 bean,将会注入 id 与 属性名相同的那个 bean。
package com.springanno.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao { }
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { /** * 默认状况下,若是容器中没有该属性类型对应的 bean,那么将会抛出异常 * 可经过指定 @Autowired 的属性 required = false 让这次的自动装配没必要须,此时容器中若是不存在该类型 bean 就不会抛出异常 */ @Autowired(required = false) private UserDao userDao; public void printDao() { System.out.println(userDao); } }
package com.springanno.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.springanno") public class MainConfig { }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); UserService userService = applicationContext.getBean(UserService.class); System.out.println(userService); userService.printDao(); /* com.springanno.service.UserService@60dcc9fe com.springanno.dao.UserDao@222114ba */
@Autowired 不只能够用在属性上,还能够用在方法上:
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { private UserDao userDao; /* 将会从容器中找到与参数类型相同的 bean 传入来执行该方法 */ @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void printDao() { System.out.println(userDao); } }
也能够标注在构造器上:
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { private UserDao userDao; /* 将会从容器中找到与参数类型相同的 bean 传入来执行该构造器来建立 UserService 实例 */ @Autowired public UserService(UserDao userDao) { this.userDao = userDao; } public void printDao() { System.out.println(userDao); } }
不只如此,还能够标注在参数上:
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { private UserDao userDao; /* 将会从容器中找到与参数类型相同的 bean 传入来执行该构造器来建立 UserService 实例 */ public UserService(@Autowired UserDao userDao) { this.userDao = userDao; } public void printDao() { System.out.println(userDao); } }
若是当前组件只有一个有参构造器, @Autowired 能够省略不写:
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.stereotype.Service; @Service public class UserService { private UserDao userDao; /* 当前组件只有一个有参构造器 将会从容器中找到与参数类型相同的 bean 传入来自动执行该构造器来建立 UserService 实例 */ public UserService (UserDao userDao) { this.userDao = userDao; } public void printDao() { System.out.println(userDao); } }
经过 @Bean 标注的方法注册 bean 时,该方法的参数也会默认从容器中获取:
package com.springanno.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao { public UserDao(){} }
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.stereotype.Service; @Service public class UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void printDao() { System.out.println(userDao); } }
package com.springanno.config; import com.springanno.dao.UserDao; import com.springanno.service.UserService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.springanno") public class MainConfig { @Bean("userService2") public UserService userService(UserDao userDao){ UserService userService = new UserService(); userService.setUserDao(userDao); return userService; } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); UserService userService = (UserService) applicationContext.getBean("userService2"); UserDao userDao = applicationContext.getBean(UserDao.class); userService.printDao(); System.out.println(userDao); /* com.springanno.dao.UserDao@21507a04 com.springanno.dao.UserDao@21507a04 */
能够经过 @Qualifier 与 @Autowired 搭配使用来指定这次要装配 bean 的 id,以下:
package com.springanno.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao { public UserDao(){} }
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Service public class UserService { @Qualifier("userDao") // 指定装配 id 为 userDao 的 bean @Autowired private UserDao userDao; public void printDao(){ System.out.println(userDao); } }
package com.springanno.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.springanno") public class MainConfig { }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); UserService userService = applicationContext.getBean(UserService.class); System.out.println(userService); userService.printDao(); /* com.springanno.service.UserService@60dcc9fe com.springanno.dao.UserDao@222114ba */
@Primary 也是用来对自动装配进行控制的,他用来指定当容器中存在多个类型相同的 bean 时,自动装配优先装配哪一个 bean,和 @Bean 一块儿使用。固然,它不能和 @Qualifier 同时使用。
package com.springanno.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao { public UserDao(){} }
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserDao userDao; public void printDao(){ System.out.println(userDao); } }
package com.springanno.config; import com.springanno.dao.UserDao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration @ComponentScan("com.springanno") public class MainConfig { @Primary // id 为 userDao2 的 bean 优先装配 @Bean public UserDao userDao2() { return new UserDao(); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); UserService userService = applicationContext.getBean(UserService.class); System.out.println(userService); userService.printDao(); UserDao userDao = (UserDao) applicationContext.getBean("userDao2"); System.out.println(userDao); /* com.springanno.service.UserService@3b2da18f com.springanno.dao.UserDao@5906ebcb com.springanno.dao.UserDao@5906ebcb */
@Resource 注解(JSR250 中定义)至关于 @Autowired 和 @Qualifier 注解一块儿使用,既能完成自动装配,也能指定要装配 bean 的 id,不支持 @Primary 注解。
package com.springanno.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao { public UserDao(){} }
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class UserService { @Resource(name = "userDao2") private UserDao userDao; public void printDao(){ System.out.println(userDao); } }
package com.springanno.config; import com.springanno.dao.UserDao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.springanno") public class MainConfig { @Bean public UserDao userDao2() { return new UserDao(); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); UserService userService = applicationContext.getBean(UserService.class); System.out.println(userService); userService.printDao(); UserDao userDao = (UserDao) applicationContext.getBean("userDao2"); System.out.println(userDao); /* com.springanno.service.UserService@2d9d4f9d com.springanno.dao.UserDao@4034c28c com.springanno.dao.UserDao@4034c28c */
@Inject 注解(JSR330 中定义)使用与 @Autowired 注解一致,只是没有属性。
package com.springanno.dao; import org.springframework.stereotype.Repository; @Repository public class UserDao { public UserDao(){} }
package com.springanno.service; import com.springanno.dao.UserDao; import org.springframework.stereotype.Service; import javax.inject.Inject; @Service public class UserService { /* 与 Autowired 相同,需导包 <dependency> <groupId>javax.inject</groupId> <artifactId>com.springsource.javax.inject</artifactId> <version>1.0.0</version> </dependency> */ @Inject private UserDao userDao; public void printDao() { System.out.println(userDao); } }
package com.springanno.config; import com.springanno.dao.UserDao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration @ComponentScan("com.springanno") public class MainConfig { @Primary @Bean public UserDao userDao2() { return new UserDao(); } }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); UserService userService = applicationContext.getBean(UserService.class); System.out.println(userService); userService.printDao(); UserDao userDao = (UserDao) applicationContext.getBean("userDao2"); System.out.println(userDao); /* com.springanno.service.UserService@2aa5fe93 com.springanno.dao.UserDao@5c1a8622 com.springanno.dao.UserDao@5c1a8622 */
@Autowired 是 Spring 定义的,而 @Resource 和 @Inject 是Java 规范中定义的。
若是咱们自定义的组件想要使用 Spring 容器底层的一些组件,例如 ApplicationContext、BeanFactory 等,可让自定义组件实现相应的 Aware 接口,Spring 容器启动时会经过接口的回调给咱们注入相应的组件。
package com.springanno.service; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; @Service("testUserServer") public class UserService implements ApplicationContextAware, BeanNameAware, EnvironmentAware { public void setBeanName(String beanName) { System.out.println(beanName); } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println(applicationContext.getBean("testUserServer")); } public void setEnvironment(Environment environment) { System.out.println(environment); } }
package com.springanno.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.springanno") public class MainConfig { }
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); /* testUserServer StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[MapPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]} com.springanno.service.UserService@3f56875e */
下面是 Spring 提供的继承了 Aware 接口的类:
ApplicationEventPublisherAware (org.springframework.context)
NotificationPublisherAware (org.springframework.jmx.export.notification)
MessageSourceAware (org.springframework.context)
BeanFactoryAware (org.springframework.beans.factory)
EnvironmentAware (org.springframework.context)
EmbeddedValueResolverAware (org.springframework.context)
ResourceLoaderAware (org.springframework.context)
ImportAware (org.springframework.context.annotation)
LoadTimeWeaverAware (org.springframework.context.weaving)
BeanNameAware (org.springframework.beans.factory)
BeanClassLoaderAware (org.springframework.beans.factory)
ApplicationContextAware (org.springframework.context)
一、建立被代理类:
package com.springanno.service; public class CalculateService { public Integer div(int i,int j){ return i/j; } }
二、编写切面类:
package com.springanno.aspects; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import java.util.Arrays; @Aspect public class LogAspect { // 若是要在别的类引用这个切入点表达式,能够使用 com.springanno.aspects.LogAspect.pc() @Pointcut(value = "execution(* com.springanno.service.CalculateService.div(..))") public void pc() { } @Before("pc()") public void logStart(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); String methodName = joinPoint.getSignature().getName(); System.out.printf("%s 运行了,参数为 %s \n", methodName, Arrays.toString(args)); } @After("pc()") public void logEnd(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println(methodName + " 执行完毕"); } @AfterReturning(value = "pc()", returning = "result") public void logReturn(JoinPoint joinPoint, Object result) { // 注意,若是使用 JoinPoint 参数,该参数只能在第一个位置 String methodName = joinPoint.getSignature().getName(); System.out.printf("%s 运行了,结果为 %s \n", methodName, result); } @AfterThrowing(value = "pc()",throwing = "ex") public void logException(JoinPoint joinPoint,Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.printf("%s 出现异常,异常信息为 %s \n", methodName, ex); } }
三、将被代理类与切面类注册到容器,使用 @EnableAspectJAutoProxy 注解开启切面自动代理功能:
package com.springanno.config; import com.springanno.aspects.LogAspect; import com.springanno.service.CalculateService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @EnableAspectJAutoProxy // 开启切面自动代理功能 @Configuration public class MainConfig { @Bean public CalculateService calculateService(){ return new CalculateService(); } @Bean public LogAspect logAspect(){ return new LogAspect(); } }
四、测试:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); CalculateService calculateService = applicationContext.getBean(CalculateService.class); calculateService.div(4, 1); /* div 运行了,参数为 [4, 1] div 执行完毕 div 运行了,结果为 4 */
updating....