学习路线
1.容器
spring认为所有的组件都应该放在容器中,通过容器的自动装配来使用
基于注解开发时 配置类就等同于之前使用的配置文件
@Configuration 表示这是一个配置类
@Target({ElementType.TYPE})//只能标记在类上
@Retention(RetentionPolicy.RUNTIME)//储存
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
boolean proxyBeanMethods() default true;
}
1.1bean注解
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})//标记在方法和注解类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")//标记用于表示bean的id
String[] name() default {};
/** @deprecated */
@Deprecated
Autowire autowire() default Autowire.NO;
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default "(inferred)";
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
/**
* 这是一个配置类
*/
public class MainConfig {
@Bean
/**
* 给容器注册一个bean
* 返回值为bean的类
* id默认是用方法名做id
*/
public person person(){
return new person();
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class mainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
person bean = applicationContext.getBean(person.class);
System.out.println(bean);
}
}
@componentScan包扫描注解
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})//标记在类上
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")//指定扫描的包 可以是数组 也就是指定扫描的多个包
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
String resourcePattern() default "**/*.class";
boolean useDefaultFilters() default true;
//ComponentScan.Filter是注解写在下面
ComponentScan.Filter[] includeFilters() default {};//扫描时包含哪些注解
ComponentScan.Filter[] excludeFilters() default {};//扫描时排除那些注解
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;//按照注解规则,这是一个枚举类
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
public enum FilterType {
ANNOTATION,//按照注解类
ASSIGNABLE_TYPE,//按照指定的类 如{BookService.class}这样写
ASPECTJ,//
REGEX,//按照正则表达式
CUSTOM;//自定义规则,要写一个TypeFilter实现类
private FilterType() {
}
}
@ComponentScan(value = {},includeFilters = {
@ComponentScan.Filter(Type= FilterType.ANNOTATION,classes = {Service.class, Controller.class})
})
/**
* 标记包扫描
* value里表示的指定的包
* includeFilters扫描策略,Type= FilterType.ANNOTATION按照注解进行包含
* 用于扫描指定包下的spring注解如:@service @component @controller @reporsity等
* 标记在类上
*/
Scope注解设置组件作用域
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
@AliasFor("scopeName")
String value() default "";
@AliasFor("value")
String scopeName() default "";
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
@Scope(value = "Prototype")//""singleton原型
public person person(){
return new person();
}
@lazy 设置bean懒加载
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
boolean value() default true;
}
标记在方法或者类上用于表示被标记的组件开启懒加载
也就是不会再创建ioc容器时创建bean而是在被调用时创建
@conditional 按条件注册bean
conditional注解使用时传入的value是一个condition对象
我们要自己编写实现了condition接口的具体对象
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}
public class MyCondition implements Condition {
@Override
/**
* ConditionContext:判断条件可以使用的上下文环境
* AnnotatedTypeMetadata:当前标注了condition注解的注释信息
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//bean工厂
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//获取环境信息
Environment environment = conditionContext.getEnvironment();
//获取bean定义注册器
BeanDefinitionRegistry registry = conditionContext.getRegistry();
//
String property = environment.getProperty("os.name");
if (property.contains("Windows")){
return true;
}
return false;
}
}
//具体使用时
@Bean("person2")
@Conditional({MyCondition.class})
public person person2(){
return new person();
}
@import 给容器快速导入组件
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}~
1.第一种使用方法
@Import(person.class)
直接标记在类上
注册的类的id为类的全类名
@Import(person.class)
public class MainConfig {~
2.通过ImportSelector进行注册
需要自己创建一个实现了ImportSelector接口的对象传入到import的value中
public class MyImportSelector implements ImportSelector {
@Override
//返回值就是要导入到容器里的类的全类名
//annotationMetadata可以获取当前类所标的所有的注解的注解的信息
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//string数组里放的时要实现类的全类名
return new String[]{"person"};
}
}~
@Import(MyImportSelector.class)
public class MainConfig {~
3.通过ImportBeanDefinitionRegistrar对象注册
创建一个ImportBeanDefinitionRegistrar~
接口的实现类传入到import的value属性值中
public class BeanDefination implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata 被标记类的注释信息
* @param registry 注册bean定义
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
registry.registerBeanDefinition("person",new RootBeanDefinition(person.class));
}
}~
@Import(BeanDefination.class)
public class MainConfig {~
~
@FactoryBean注册组件
创建一个实现了factorybean接口的实现类
并通过@bean的方式存入容器,方法的名称就是类的id
public class personTest implements FactoryBean {
@Override
//返回单个实现类
public Object getObject() throws Exception {
return new person();
}
@Override
//实现类的类对象数组
public Class<?> getObjectType() {
return null;
}
@Override
//判断是否为单例
public boolean isSingleton() {
return false;
}
}~
//使用时
@Bean
public FactoryBean factoryBean(){
return new personTest();
}~
设置bean的生命周期
外部资源文件
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
String name() default "";
String[] value();//配置文件的路径从class path开始可以一次导入多个
boolean ignoreResourceNotFound() default false;
String encoding() default "";
Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}
~
取出配置文件的属性值时通过value(${…})
自动装配
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;//这个属性可以设置是否必须注入组件如果为 true那么
}~
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}~
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary {
}~
/**
- 自动装配:
-
spring利用依赖注入自动存入相应的组件
- 注解:
-
@Autowired:自动注入(优先按照类型找到并赋值,如果同时有多个相应类型的组件
-
就对属性名作为组件id到容器内查找组件并赋值)
-
@Qualifier:按照指定的id装入,如果容器中没有指定id的组件,那么会报出异常
-
@Primary:这个不能与Qualifier一起使用,他的作用是对某个组件指定首选,让这个组件优先级最高
*/~
Aware接口
Profile根据环境注册bean
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({ProfileCondition.class})
public @interface Profile {
String[] value();//环境标识
}~
@PropertySource({"classpath:db.properties"})
public class MainConfig {
@Profile("test")
@Bean("caohao")
public person person1(){
person person = new person();
person.setName("test");
return person;
}
@Profile("Dev")
@Bean("caohao")
public person person2(){
person person = new person();
person.setName("dev");
return person;
}
public class mainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("Dev");
applicationContext.register(MainConfig.class);
applicationContext.refresh();
person caohao = (person) applicationContext.getBean("caohao");
System.out.println(caohao.getName());