在学习spring中的注解开发之前,必须了解java中的反射和注解:
当一个项目很大的时候,xml 文件就会有很多,配置起来就稍微有点麻烦,所以,可以使用注解来代替在xml的相关配置。
用在类上,指明这个类是配置类,相当于是一个只有名称空间的xml文件,有了配置类,就可以不用写xml文件了。
用在方法上,给IOC容器中注册一个bean,id 默认为方法名,也可以使用value属性指定,类型是方法的返回值类型。相当于在xml文件中写<bean id=" " class=" "/></bean>
。如果方法中有参数,参数默认从容器中获取。
`
@//表示这个类是配置类,代替xml文件 @Configuration public class MainConfig { @Bean //在IOC容器中注册bean,类型是返回值类型,id默认是方法名 public Person person(){ return new Person("张三",20); } }
用在配置类上,开启包扫描,开启之后,类只要标注了@Controller、@Service、@repository、@Componmente
这四个注解中的任何一个,都会在容器中注册,相当于在xml文件中使用<context:componment-scan value=" ">
- value:指定要扫描的包
- excludeFilters :指定扫描的时候按照什么规则排除哪些组件,这个属性的类型是一个Filter注解类型的数组,Filter注解中,有type(按照什么类型进行排除)、classes(排除type类型的类)等属性
@ComponentScan(value="ewen", excludeFilters = { 排除@Repository注解 @Filter(type=FilterType.ANNOTATION,classes={Repository.class}) })
- includeFilters:指定扫描的时候只包含那些类型的组件,使用这个属性的时候,需要让
useDefaultFilters=false
(@CoponentScan的属性),来禁用默认的过滤规则,默认使用的是不扫描哪些些组件
@ComponentScan(value="ewen", includeFilters ={ //只要@Service注解 @Filter(type=FilterType.ANNOTATION, classes={Service.class, Repository.class}) }, useDefaultFilters = false)
@Filter这个注解中,type的类型是FilterType枚举类,枚举类中有以下几个值
- FilterType.ANNOTATION:按照注解(常用),classes是注解.class
- FilterType.ASSIGNABLE_TYPE:按照给定的类型(常用),classes是类名.class
- FilterType.ASPECTJ:使用ASPECTJ表达式
- FilterType.REGEX:使用正则指定
- FilterType.CUSTOM:使用自定义规则(自定义类,实现FilterType接口),classes为自定义类.class
自定义过滤规则,就是写一个类,实现FilterType接口,实现match方法(过滤规则),当扫描一个类时,会执行match方法,如果返回true,表示,符合规则,将这个类在IOC容器中注册,返回false,不在容器中注册。
@ComponentScan(value="ewen", includeFilters = { @Filter(type=FilterType.CUSTOM, classes={MyTypeFilter.class}) } , useDefaultFilters = false )
自定义规则(只要含有 “er” 的类)
public class MyTypeFilter implements TypeFilter { /** * @param metadataReader:读取到的当前正在扫描的类信息 * @param metadataReaderFactory:可以获取到其他类的任何信息 * @return 当进行包扫描时,使用自定义过滤规则,扫描到的类来与这个方法中定义的规则匹配 * 如果返回true,代表符合规则,将这个类注入到容器中,返回false,代表不符合规则 * @throws IOException */ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //获得当前正在扫描类的注解信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //获取当前正在扫描的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前正在扫描类的路径 Resource resource = metadataReader.getResource(); String name = classMetadata.getClassName(); if(name.contains("er")){ return true; } return false; } }
指定bean的作用范围,有如下四个属性:
懒加载,容器启动时,不创建对象,获取时才会创建,只有当是bean是单例的(singleton)时才有用
用在方法上,按照一定条件进行判断,满足条件给容器注册bean,注意需要和@Bean一起使用。也可以把这个注解放在类上,类中的bean满足条件才可以在容器中注册
需要定义一个条件类,实现Condition接口,实现match方法,如果这个方法返回true,则符合条件,注册bean
//如果是Windows操作系统,给容器中注册bill @Conditional(WindowsCondition.class) @Bean public Person person01(){ return new Person("bill", 60); }
自定义条件类
//判断当前操作系统是不是Windows public class WindowsCondition implements Condition { /** * * @param conditionContext:判断条件能使用的上下文环境 * @param annotatedTypeMetadata:注释信息 * @return 如果返回true,代表符合条件,返回false,表示不符合条件 */ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { /*通过conditionContext可以获得很多有用的信息, 可以使用这些信息,来设置很多条件 //1.获取IOC使用的工厂BeanFactory ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory(); //2.获取类加载器 ClassLoader classLoader = conditionContext.getClassLoader(); //4.获取bean定义的注册类,通过这个类可以注册、查询、移除IOC容器中的bean BeanDefinitionRegistry registry = conditionContext.getRegistry(); */ //3. 获取运行时的环境信息 Environment environment = conditionContext.getEnvironment(); //获取当前的操作系统名字 String osName = environment.getProperty("os.name"); //判断当前操作系统是不是Windows 10 if(osName.contains("Windows")){ return true; } return false; } }
给容器中注册组件(bean),前面已经写了两种:
@Import(类名.class) 快速给容器中导入一个组件,id为类的全路径名,用在类上,属性为class类型的数组
比如,在容器中注册Color、Red类
@Configuration //@Import:快速在容器中注册组件,id为类的全路径名 @Import({Color.class, Red.class}) public class MainConfig02 { 。。。}
@Configuration /* @Import:快速在容器中注册组件,id为类的全路径名 类名.class 选择器类.class */ @Import({Color.class, Red.class, MyImportSelector.class}) public class MainConfig02 { 。。。}
自定义选择器类
//选择器类 public class MyImportSelector implements ImportSelector { /** * @param importingClassMetadata:可以获得@Import标注的类的所有注解信息 * @return 返回一个String数组,里面要注册的bean的全路径名,id是全路径名 */ public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"ewen.bean.Blue"}; } }
@Configuration /* @Import:快速在容器中注册组件,id为类的全路径名 类名.class 选择器类.class:实现ImportSelector接口的类 注册类.class:实现ImportBeanDefinitionRegistrar接口的类 */ @Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig02 { 。。。}
注册类
//注册类 public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** AnnotationMetadata:@Import标注类的注解信息 BeanDefinitionRegistry:bean的注册类,通过这个类,调用registerBeanDefinition方法 可以手动的在容器中注册bean。也可以用这个类中的方法进行查询、移除bean */ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //先判断IOC容器中是否有蓝色和红色,如果都有,就注册一个RainBow boolean b1 = registry.containsBeanDefinition("ewen.bean.Blue"); boolean b2 = registry.containsBeanDefinition("ewen.bean.Red"); if(b1 && b2){ //指定bean的定义信息(bean的类型、作用域等等) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); //指定bean的id registry.registerBeanDefinition("rainBow",beanDefinition); } } }
使用spring提供的FactoryBean(工厂bean)也可以给容器注册bean。FactoryBean 是一个接口,里面有三个方法,getObject,获取对象,getObjectType,获取对象类型,isSingleton,是否是单例模式。定义一个类实现FactoryBean接口,实现上面三个方法,然后在配置类中,使用@Bean注解来注册这个类,需要注意的是,通过getBean方法获取的是在getObject中生成的对象,而不是FactoryBean对象,可以在name前面加一个“&”获取FactoryBean 对象。
//自定义的FactoryBean,通过这个FactoryBean来给容器注册Bean public class ColorFactoryBean implements FactoryBean<Color> { public Color getObject() throws Exception { return new Color(); } public Class<?> getObjectType() { return Color.class; } //返回true,是单例,返回false不是单例 public boolean isSingleton() { return true; } }
配置类
@Bean public ColorFactoryBean colorFactoryBean(){ return new ColorFactoryBean(); }
bean创建—初始化—销毁的过程
我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候来调用自定义的初始化和销毁方法。
指定bean的初始化和销毁方法
BeanPostProcessor 原理
- 调用populateBean方法给bean赋好值,执行initializeBean方法
- nitializeBean方法中主要执行applyBeanPostProcessorsBeforeInitialization 遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,一但返回null,跳出for循环,不会执行后面的postProcessBeforeInitialization方法
- 执行完applyBeanPostProcessorsBeforeInitialization ,执行初始化方法,再执行applyBeanPostProcessorsAfterInitialization方法
Spring底层对 BeanPostProcessor 的使用
bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async等都使用的是xxx BeanPostProcessor。
xml中是在标签下使用进行属性注入的,可以使用@Value注解代替,@Value中,可以写:
自动注入,默认优先根据类型在容器中找对应的组件,将组件赋给@Autowired下的属性,如果容器中有多个相同类型的组件,会将属性名作为id在容器中查找组件。
如果容器中没有相同类型的bean或者指定id的bean,会报错,可以修改required属性为false(默认为true),就不报错了。
@Autowired 还可以用在构造器、方法、参数上,参数默认从容器中获取。
@Resouce 和 @Inject 都可以自动注入,@Resource(name=””) 是根据bean的id自动注入的,不支持@Primary来指定首选bean。使用@Inject 要导入javax.inject包,注解里没有属性。这两个注解式java规范的,@Autowired是spring定义的。
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx),自定义组件类可以实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware,把Spring底层一些组件注入到自定义的Bean中;
xxxAware:底层使用xxxAwareProcessor, 如ApplicationContextAware ==》ApplicationContextAwareProcessor。在bean中获取applicationContext。
//实现ApplicationContextAware接口,可以在Color类中获得applicationContext //实现BeanNameAware接口,可以获得bean的id //实现EmbeddedValueResolverAware接口,可以解析字符串 @Component public class Color implements ApplicationContextAware, BeanNameAware,EmbeddedValueResolverAware { private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public void setBeanName(String name) { System.out.println("bean 的name:" + name); } //StringValueResolver解析字符串 public void setEmbeddedValueResolver(StringValueResolver resolver) { String s = resolver.resolveStringValue("你好${os.name} #{18 * 20}"); System.out.println("解析的字符串:" + s); }
指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
比如,在tes环境下,将dataSourceTest注册到容器,开发dev环境下,将dataSourceDev注册到容器
参考:
Spring注解驱动教程
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算