Spring注解驱动(上)
记录常用的spring注解
1.@Configuration 和 @Bean
spring中可以使用xml 的方式进行配置, 也可以使用 @ Configuration 来指定一个类为配置类, 并使用 @Bean 来对spring容器进行注入.方法名即是id
@Configuration //声明这个类为配置类
public class MainConfig {
//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
并使用如下方式获取容器,并获取注入的对象
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); //获取容器
Person bean = applicationContext.getBean(Person.class);//获取对象
2. @ComponentScan 包扫描注解
在xml中,我们使用 :<context:component-scan base-package="com.test.****"/>
来进行包扫描,只要是加了 @Controller
,@service
,@Repository
,@Component
这四个注解的类,都会自动的被注入到容器中.同样,我们也可以使用 注解的方式进行配置,在@Configuration
注解声明的配置类上加上 @ComponentScan
注解:
@Configuration //告诉Spring这是一个配置类
@ComponentScan(value="com.test") // 扫描com.test下的类
public class MainConfig {
//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
在ComponentScan中还有很多属性,可以进行定义扫描规则:
value : 指定扫描的包路径
excludeFilters :指定扫描的时候按照什么规则排除那些组件 ,接受一个 @Filter 的数组
例:
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
, 按照注解类型的方式进行过滤(还有很多种),过滤@Controller
注解的类.includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件, 使用方法和excludeFilters一样,但是还要将spring的自动扫描规则关闭,才能生效(和xml相似),设置属性 :
useDefaultFilters = false
如果需要多种过滤规则时,可以使用@ComponentScans
注解 ,可以接受多个@ComponentScan
下面是@Filter
的type属性的详细配置:
按照注解排除或注入: type=FilterType.ANNOTATION(常用)
按照给定的类型 : type=FilterType.ASSIGNABLE_TYPE (常用)
使用ASPECTJ表达式 : type=FilterType.ASPECTJ(不常用)
使用正则表达式 : type=FilterType.REGEX(不常用)
使用自定义的规则(实现TypeFilter) : type=FilterType.CUSTOM(不常用,但很灵活)
例:
public class MyTypeFilter implements TypeFilter { /**
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类信息的
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){
return true;
}
return false;
} }
本例中的过滤规则是类名中带有er的进行注入,按照返回值得true或false来决定是否注入
3.@Scope 域注解
调整注入对象的作用域,可以设置为单实例或多实例,例:
@Scope
@Bean
public Person person(){
System.out.println("给容器中添加Person....");
return new Person("张三", 25);
}
Scope注解的具体取值:
- prototype, 多实例,IOC容器在启动时不会创建对象,每次获取的时候才会去调用方法创建对象
- singleton,单实例,默认的取值,IOC在启动时就会创建对象,每次获取都是同一个对象,直接从容器中拿
- request,同一次请求创建一个实例 (不用)
- session 同一个session创建一个实例(不用)
在使用单实例加载方式的时候,在IOC容器启动时,就创建对象,如果想要在获取时,在创建,可以使用@Lazy
注解,使Bean懒加载
4. @Conditional 判断Bean是否注入
在某些情况,我们需要根据情况来决定是否注入类,获取注入不同的类,这时我们就需要使用@Conditional
注解
我们需要继承Condition类,例:
//判断是否liunx系统
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO是否linux系统
//1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前环境信息
Environment environment = context.getEnvironment();
//4、获取到bean定义的注册类(管理类,可以判断是否注入,创建 ,删除注入的Bean)
BeanDefinitionRegistry registry = context.getRegistry();
//获取操作系统属性
String property = environment.getProperty("os.name");
//可以判断容器中的bean注册情况,也可以给容器中注册bean
//判断容器中是否有person类
boolean definition = registry.containsBeanDefinition("person");
if(property.contains("linux")){
return true;
}
return false;
}
}
使用:
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
如果系统是liunx 才会注入该Bean ,如果不是,将不会注入, 如果将该类加载配置类上,则表示,只有当条件满足时,才会加载配置类中的Bean
5.@Import注解 快速给容器中导入一个组件
通过注解注入对象的方式,已经有两种,分别是:
@ComponentScan
注解进行包扫描,这主要针对自己写的类,只有自己写的类,才可以方便我们家@Controller/@Service/@Repository/@Component 这四个注解@Bean
向容器中注入一个对象,可以方便我们导入第三方的类
第三种方法,就是使用@Import
注解.例
@Import({Color.class,Red.class)
在配置类上加上该注解代表 向容器中注入Color类和 Red类,默认的id是类的全类名
Import注解除了可以直接指定导入的对象外,还支持更加丰富的注入方式
ImportSelector 的实现类:
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector { //返回值,就是到导入到容器中的组件全类名
//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
//importingClassMetadata
//方法不要返回null值
return new String[]{"com.test.bean.Blue","com.test.bean.Yellow"};
}
}
@Import({MyImportSelector.class})
返回的数组就是需要注入的Bean的全类名数组
ImportBeanDefinitionRegistrar 的实现类:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /**
* AnnotationMetadata:当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类;
* 把所有需要添加到容器中的bean;调用
* BeanDefinitionRegistry.registerBeanDefinition手工注册进来
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean definition = registry.containsBeanDefinition("com.test.bean.Red");
boolean definition2 = registry.containsBeanDefinition("com.test.bean.Blue");
if(definition && definition2){
//指定Bean定义信息;(Bean的类型,Bean。。。)
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
//注册一个Bean,指定bean名
registry.registerBeanDefinition("rainBow", beanDefinition);
}
} }
@Import({MyImportBeanDefinitionRegistrar.class})
在方法内部进行操作,使用BeanDefinitionRegistry 对象进行注入
6.FactoryBean 注册组件
这又是一个向容器中注入对象的方法, 首先先实现 FactoryBean接口
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是单例?
//true:这个bean是单实例,在容器中保存一份
//false:多实例,每次获取都会创建一个新的bean;
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
并将该工厂类注册到容器中
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
但是当我们通过id获取时,却是getObject方法返回的对象Color,如果我们想获取到工厂对象的本身,可以在id的前面加'&' 即&colorFactoryBean
即可获取到工厂对象的本身.
7.指定注入对象的创建和销毁方法
在xml中,可以使用 init-method和destroy-method 两个属性,指定Bean的初始化方法和销毁方法,如果使用注解,则可以用@Bean
的属性来指定
@Bean(initMethod="init",destroyMethod="detory")
public Car car(){
return new Car();
}
如上例,就指定初始化方法为init,销毁方法为detoty.
Bean的初始化方法是在Bean创建后,调用方法,进行赋值,Bean的销毁方法,和Bean是否是单实例有关,如果Bean是单实例的,销毁方法会在容器关闭时调用,如果是多例的,在从容器中取出该对象时,容器就不进行管理了,所以在容器关闭时,是不会调用销毁方法的.
另一种方法就是实现两个接口 ,一个是InitializingBean 实现的方法就是初始化方法, DisposableBean 实现的方法就是销毁方法.
还有一种是使用注解标注Bean的方法 . @PostConstruct 在 Bean创建完成并且属性赋值完成,来执行初始化方法@PreDestroy : 在容器销毁Bean之前通知我们进行的清理工作
最后一种方式使用的是 通知的方式 实现BeanPostProcessor 接口 ,并将实现类注入到容器中,就可以实现在任何Bean的任何初始化方法执行前执行postProcessBeforeInitialization方法, 并在任何初始化方法之后执行postProcessAfterInitialization方法.(spring源码中大量使用)
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
return bean;
}
}
8.@Value 给属性赋值
使用@Value
注解给属性赋值,他的使用方法 和xml文件中 value属性一致,可以直接赋值字符串:@Value("张三")
,或者是Spring的表达式:@Value("#{20/2}")
, 也可以取出配置文件中的值(环境变量中值):@Value("${name}")
.
Spring注解驱动(上)的更多相关文章
- 【Spring注解驱动开发】组件注册-@ComponentScan-自动扫描组件&指定扫描规则
写在前面 在实际项目中,我们更多的是使用Spring的包扫描功能对项目中的包进行扫描,凡是在指定的包或子包中的类上标注了@Repository.@Service.@Controller.@Compon ...
- 【Spring注解驱动开发】自定义TypeFilter指定@ComponentScan注解的过滤规则
写在前面 Spring的强大之处不仅仅是提供了IOC容器,能够通过过滤规则指定排除和只包含哪些组件,它还能够通过自定义TypeFilter来指定过滤规则.如果Spring内置的过滤规则不能够满足我们的 ...
- 【Spring注解驱动开发】使用@Scope注解设置组件的作用域
写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...
- 【Spring注解驱动开发】使用@Lazy注解实现懒加载
写在前面 Spring在启动时,默认会将单实例bean进行实例化,并加载到Spring容器中.也就是说,单实例bean默认在Spring容器启动的时候创建对象,并将对象加载到Spring容器中.如果我 ...
- 【Spring注解驱动开发】使用@Import注解给容器中快速导入一个组件
写在前面 我们可以将一些bean组件交由Spring管理,并且Spring支持单实例bean和多实例bean.我们自己写的类,可以通过包扫描+标注注解(@Controller.@Servcie.@Re ...
- 【Spring注解驱动开发】在@Import注解中使用ImportSelector接口导入bean
写在前面 在上一篇关于Spring的@Import注解的文章<[Spring注解驱动开发]使用@Import注解给容器中快速导入一个组件>中,我们简单介绍了如何使用@Import注解给容器 ...
- 【Spring注解驱动开发】面试官:如何将Service注入到Servlet中?朋友又栽了!!
写在前面 最近,一位读者出去面试前准备了很久,信心满满的去面试.没想到面试官的一个问题把他难住了.面试官的问题是这样的:如何使用Spring将Service注入到Servlet中呢?这位读者平时也是很 ...
- 【Spring注解驱动开发】在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean
写在前面 在前面的文章中,我们学习了如何使用@Import注解向Spring容器中导入bean,可以使用@Import注解快速向容器中导入bean,小伙伴们可以参见<[Spring注解驱动开发] ...
- 【Spring注解驱动开发】如何使用@Bean注解指定初始化和销毁的方法?看这一篇就够了!!
写在前面 在[String注解驱动开发专题]中,前面的文章我们主要讲了有关于如何向Spring容器中注册bean的知识,大家可以到[String注解驱动开发专题]中系统学习.接下来,我们继续肝Spri ...
随机推荐
- redhat7和redhat6混合搭建文档
1.下载cm对应redhat7的版本.2.修改/opt/cloudera/cm-5.10.0/etc/cloudera-scm-agent/config.ini成为中心机器hostname/ip(ma ...
- java 3des加密问题记录
3des加密有不同的加密模式和填充模式,这个网上很多不多说了,只要保证加解密的时候加密模式和填充模式保持一致就可以了 首先对于密钥的生成,java中有2种方式: 1.第一种,采用ECB模式和不填充模式 ...
- 深度探索C++对象模型之第二章:构造函数语意学之Copy constructor的构造操作
C++ Standard将copy constructor分为trivial 和nontrivial两种:只有nontrivial的实例才会被合成于程序之中.决定一个copy constructor是 ...
- sql (9) COUNT
COUNT() 函数返回匹配指定条件的行数.语法SQL COUNT(column_name) 语法COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入):新建表 Stude ...
- Android studio 添加引用Module项目 与 设置Module项目的Libs的Jar在主项目里使用
前言 添加引用Module项目 设置Module项目的Libs的Jar在主项目里使用 1.在项目里添加libs包,并且加入jar 2.设置这个module项目的build.gradle depende ...
- AOP-面向切面编程-1
将方法类比成一个积木,哪里需要执行插到哪里 视野角度就是将一个程序比作几条绳子的集合,每个集合是一堆方法的集合,那么把绳子截断,绳子的切面就是一堆方法中一个方法与另一个方法的交界处,将你需要的方法切入 ...
- CSS3——伸缩布局及应用
CSS3在布局方面做了非常大的改进,使得我们对块级元素的布局排列变得十分灵活,适应性非常强,其强大的伸缩性,在响应式开中可以发挥极大的作用. 主轴:Flex容器的主轴主要用来配置Flex项目,默认是水 ...
- hibernate_01_SSH环境搭建
1.maven工程pom.xml文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="h ...
- SpringBoot--springboot启动类和controller的配置
作为一个springboot初学者,在探索过程中难免遇到一些坑,边看书边动手,发现书本中的版本是1.0,而我使用的是最新版2.0,所以有些东西不能完全按照书本进行操作,因为2.0中已经不支持1.0中的 ...
- 4_1.springboot2.xWeb开发使用thymeleaf
1.简介 如果使用SpringBoot: 1).创建SpringBoot应用,选中我们需要的模块: 2).SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来: ...