spring系列(一)基本组件
类级别注解
-
@Component:通用注解组件,可被继承扩展为不同层次使用的专用组件.当某一个类在不属于其他典型层次中可作为选择使用
-
@Controller: 控制层,所注解的为Controller类型与最前端用户数据交互,在web 中广泛与RequestMapping等结合使用
-
@Service: 服务层,所注解的为一般业务类(如xxxServiceImpl…),负责处理某一类问题的服务.上承控制层数据;处理业务逻辑;下接数据层适配转换
-
@Repository:数据层,所注解的为最底层与数据直接打交道的类,提供CRUD基本API,以及额外的持久化等功能.一般表现形式为xxxDAO,xxxRepository等,在spring-data模块中有很多,与各类数据库及框架等有很好的适配
-
@Indexed:不属于任何层,与其他类注解结合用作提升spring扫面注解装配性能的一种索引模式.
-
使用@Indexed与@Configuration注解,并在编译中添加spring-context-indexer依赖,
-
打包后会有META-INF\spring.components,会通过该文件加载bean不再通过componentScan方式,提升注解加载性能
-
-
@Configuration:加载配置类,通过AnnotationConfigApplicationContext可以注册、扫描并创建符合条件的实例.类本身也作为一个bean被放入容器中存在
-
空壳配置类:与@ComponentScan,@ComponentScans等结合使用,通过扫描package的方式筛选出需要的bean。该配置类中不需要作任何定义bean的行为,通过AnnotationConfigApplicationContext传递scan的package给spring扫描。
@Configuration @ComponentScan("com.example.spring1") public class AppConfig { }
-
引入配置类:与@Import结合使用。可直接引入类(beanName为全路径名,需要可被构造:要么无参构造,要么注入所需构造参数到容器);通过ImportSelector接口导入类名注入;
-
Import{ModelA.class}: com.example.spring2.external.ModelA:com.example.spring2.external.ModelA@2eae8e6e
-
Import{ModelImportSelector.class}:
com.example.spring2.external.SelectorModel:com.example.spring2.external.SelectorModel@8f2ef19 -
Import{ModelImportBeanDefinitionRegistrar.class}:
registerModel:com.example.spring2.external.RegistrarModel@25ce9dc4
@Configuration @Import({ModelA.class,ModelImportSelector.class,ModelImportBeanDefinitionRegistrar.class}) public class AppConfig { @Bean @Primary public DemoService demoService(){ return new DemoService(); } @Bean(initMethod = "init",destroyMethod = "destroy") @Conditional(value = {BeanCreatorCodition.class}) public DemoController demoController(){ return new DemoController(demoService()); } @Bean public String modelAName(){ return "modelA_name"; } }
public class ModelA { private String name; public ModelA(String name){ this.name =name; } } public class SelectorModel { private String name; } // custom import component public class ModelImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{SelectorModel.class.getName()}; } } public class ModelImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { RootBeanDefinition rbd =new RootBeanDefinition(RegistrarModel.class); //register beanDefinition to IOC with given beanName beanDefinitionRegistry.registerBeanDefinition("registerModel",rbd); } }
-
-
定义配置类:当应用中其他需要被注入的bean没有加类注解(component等)时,可以统一在该配置类中定义所有需要注入的bean[一般为第三方类]。
- 同时可以管理对象间的引用
- bean的优先级[@Primary]
- bean的自定义初始化及销毁逻辑(initMethod、destroyMethod)
- 指定scope[@Scope]
- 懒加载[@Lazy]
- 条件注入[@Conditional]
- 依赖关系[@DependsOn]
@Configuration public class AppConfig { @Bean @Primary @DependsOn({"demoDAO"}) public DemoService demoService(){ return new DemoService(); } @Bean(initMethod = "init",destroyMethod = "destroy") @Conditional(value = {BeanCreatorCodition.class}) public DemoController demoController(){ return new DemoController(demoService()); } @Bean public DemoDAO demoDAO(){ return new DemoDAO(); } }
public class BeanCreatorCodition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { //get property/profile from environment Environment environment = conditionContext.getEnvironment(); //get bean info from beanFactory ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory(); //get annotated attribute info from AnnotatedTypeMetadata, created the bean if initMethod specified //get value;name;autowire;autowireCandidate;initMethod;destroyMethod; Map<String, Object> attributes = annotatedTypeMetadata.getAnnotationAttributes(Bean.class.getName()); if (attributes.get("initMethod")!=null){ return true; } return false; } }
-
-
@ComponentScan/@ComponentScans:定义需要扫描注解的bean包路径,同时可以自定义过滤规则排除或选择某些类作为最后进入容器的对象[需要disable默认filter—>useDefaultFilters = false].
enum FilterType:
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM@Configuration @ComponentScan(value = {"com.example.spring3"}, includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, CustomAnno.class}), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {AbstractService.class}), @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {CustomFilter.class}) },excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})}, useDefaultFilters = false) public class AppConfig { }
-
自定义扩展注解:CustomAnno,通过添加FilterType.ANNOTATION将该注解的类扫描进去
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CustomAnno { }
-
自定义实现ComponentScan.Filter: CustomFilter ,实现TypeFilter接口将Repository类型的类扫描进去
public class CustomFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); Set<String> annotationTypes = annotationMetadata.getAnnotationTypes(); if (annotationTypes.contains(Repository.class.getName())){ return true; } return false; } }
-
条件同时命中excludeFilters和includeFilters时,excludeFilters优先成为最后注入的条件判断,例如该测试中Controller类型的并未注入到容器中
appConfig:com.example.spring3.config.AppConfig$$EnhancerBySpringCGLIB$$b86ebffd@78e4deb0 demoDAO:com.example.spring3.dao.DemoDAO@6e9175d8 customAnnotatedModel:com.example.spring3.model.CustomAnnotatedModel@7d0b7e3c extendsService:com.example.spring3.service.ExtendsService@15bb5034
-
成员级别注解
-
@Autowired
-
当容器中有同类型的多个bean时,Autowired优先查找@Primary修饰的;同时容器中按类型查找时也按此优先查找
-
配合 @Qualifier(“demoServiceB”)使用时,按beanName从容器找符合的bean, Primary修饰失效
-
可设置required属性,需要注入的依赖对象可不存在容器中
public class DemoController { @Autowired private DemoService demoService1; //DemoServiceA @Autowired @Qualifier("demoServiceB") private DemoService demoService2;//DemoServiceB @Resource(name = "demoServiceB") private DemoService demoService3;//DemoServiceB public void print(){ System.out.println("controller invoke..."); demoService1.print(); demoService2.print(); demoService3.print(); } }
-
-
@Resource–>javax.annotation.Resource
- @Resource(name=“demoServiceB”)与@Autowired+@Qualifier(“demoServiceB”)作用相似
- 修饰的成员必须存在容器中
@Configuration
@ComponentScan("com.example.spring4")
public class AppConfig {
@Bean
public DemoController demoController(){ return new DemoController(); }
@Bean("demoService")
@Primary
public DemoService demoService(){ return new DemoServiceA(); }
@Bean("demoServiceB")
public DemoService demoServiceB(){ return new DemoServiceB(); }
}
注:Autowired和Resource对于同类型的多个实现类在容器中时,可以以Map形式注入
public class DiffController {
@Autowired
private Map<String,DemoService> demoServiceAutowire;
@Resource
private Map<String,DemoService> demoServiceMapResource;
public void print(){
System.out.println("controller invoke...");
System.out.println(demoServiceAutowire);
System.out.println(demoServiceMapResource);
}
}
其中两中形式注入结果一样,beanName->bean
{demoService=com.example.spring4.service.DemoServiceA@17f9d882, demoServiceB=com.example.spring4.service.DemoServiceB@79e4c792}
{demoService=com.example.spring4.service.DemoServiceA@17f9d882, demoServiceB=com.example.spring4.service.DemoServiceB@79e4c792}
demo 地址: github