本文共 18904 字,大约阅读时间需要 63 分钟。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.levi.java</groupId> <artifactId>spring</artifactId> <version>0.0.1-SNAPSHOT</version>
<!-- 版本变量控制 --> <properties> <!-- 源码编码 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Maven编译版本 --> <maven.compiler.version>3.1</maven.compiler.version>
<!-- 指定一下jdk的版本 ,这里我们使用jdk 1.8 ,默认是1.6 --> <java.version>1.8</java.version>
</properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.6.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> </dependencies>
<!-- 构建节点. --> <build> <plugins> <!-- 项目编译插件,所有子项目都必备的插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven.compiler.version}</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> </plugins> </build> </project> |
public class Student {
private String name;
public Student() { System.out.println("构造..."); }
public Student(String name) { super(); this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public void init(){ System.out.println("init..."); }
public void destroy(){ System.out.println("destroy..."); }
@Override public String toString() { return "Student [name=" + name + "]"; } } |
public class Student {
private String name;
public Student() { System.out.println("构造..."); }
public Student(String name) { super(); this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public void init(){ System.out.println("init..."); }
public void destroy(){ System.out.println("destroy..."); }
@Override public String toString() { return "Student [name=" + name + "]"; } } |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.levi.spring.annotations.levi01beanxml.Student"> <property name="name" value="abc"></property> </bean> </beans> |
/** * 以前是使用xml配置化时,就是使用ClassPathXmlApplicationContext */ public class L01MainTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test.xml"); Student student = (Student) applicationContext.getBean("student"); System.out.println(student.getName()); } } |
/** * @Configuration是用于定义配置类,可替换Xml配置文件,被注解的类的内部包含一个或多个被@Bean注释的方法, * 这些方法会被AnnotaionConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描, * 并用于构建bean定义,初始化Spring容器。 */ @Configuration public class L02MainConfig {
@Bean public Student student() { return new Student(); }
@Bean public Student getStudent() { return new Student(); }
public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(L02MainConfig.class); Student student = (Student) applicationContext.getBean("student"); // Student student2 = (Student) applicationContext.getBean("getStudent"); System.out.println(student); // System.out.println(student2); } } |
/** * @ComponentScan:根据定义的扫描路径,把符合扫描规则的类装配到Spring容器中。 * 参数: * value:只扫描包 * excludeFilters:指定扫描时,按照扫描规则排除哪些组件。 * includeFilters:指定扫描时,只需要包含哪些组件 * Filter.ANNOTATION:按照注解过滤 * Filter.ASPECTJ:根据Aspetj的表达式 * Filter.REGEX:按照正则表达式 * Filter.CUSTOM:自定义规则 */ @Configuration @ComponentScan(value = { "com.levi.spring.annotations.levi02scan"}, includeFilters = { @Filter(type=FilterType.ANNOTATION)}) public class ComponentScanConfig {
@Bean public Student student() { return new Student(); }
} |
/** * * @author suzhiwei */ public class MainConfig { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ComponentScanConfig.class); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String name : beanDefinitionNames) { System.out.println(name); } } } |
@Configuration public class MainConfig {
/** * @Scope:指定位于Spring容器中的实例,默认是单例。 * singleton:默认,单例。IOC容器启动时会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中获取(Map)同一个 * prototype:多实例,IOC容器启动的时候,不会去调用方法创建对象,而是每次获取的时候才会调用方法创建对象。另外,这也是为什么@Lazy对多例无效。 * request:针对Web应用,一次请求创建一个对象。 * session:同一个session创建一个实例。 */ @Scope(value = "prototype") // @Scope @Bean public Student student() { return new Student(); }
public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Student student = (Student) applicationContext.getBean("student"); Student student2 = (Student) applicationContext.getBean("student"); System.out.println(student); System.out.println(student2); } } |
@Configuration public class MainConfig {
/** * @Lazy:懒加载价值只对单例bean起作用,对于多例bean设置懒加载没有意义,因为多实例bean本来就是在使用时才创建。 * 在没有用@Lazy注释标注时,不会启动懒加载,在容器创建的时候,就会初始化bean了。 * 非懒加载的好处在于可以提前发现错误,但是消耗资源。 */ @Lazy @Bean public Student student() { return new Student(); }
public static void main(String[] args) { /* * 有@Lazy结果: * IOC * 构造对象... * * 无@Lazy结果: * 构造... * IOC */ ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); System.out.println("IOC"); Student student = (Student) applicationContext.getBean("student"); System.out.println(student); } } |
public class LeviConditional implements Condition {
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); System.out.println("正在使用的类:" + beanFactory.getClass());
String systemName = context.getEnvironment().getProperty("os.name"); System.out.println("系统类型:" + systemName); System.out.println("不同系统类型做不同的事情。"); if(systemName.contains("Windows")) { System.out.println("Windows系统允许创建"); return true; } return false; } } |
@Configuration public class MainConfig {
/** * @Conditional:只有的满足某些条件的情况下才会注入到IOC容器中 */ @Conditional(value = LeviConditional.class) @Bean public Student student() { return new Student(); }
public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Student student = (Student) applicationContext.getBean("student"); System.out.println(student); } } |
public class Boy {
} |
public class Girl {
} |
public class Person {
} |
public class Teacher {
} |
public class LeviFactoryBean implements FactoryBean<Boy> {
@Override public Boy getObject() throws Exception { return new Boy(); }
@Override public Class<?> getObjectType() { return Boy.class; }
@Override public boolean isSingleton() { return true; } } |
public class LeviImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //判断这个是否在容器内 boolean containsBeanDefinition = registry.containsBeanDefinition("com.levi.spring.annotations.levi06import.Teacher"); System.out.println("========== LeviImportBeanDefinitionRegistrar:" + containsBeanDefinition); if (containsBeanDefinition) { //如果在容器内,那么就把Girl类创建出来也加入到容器中 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Girl.class); registry.registerBeanDefinition("girl", rootBeanDefinition); } } } |
public class LeviImportSelector implements ImportSelector {
@Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { //返回全类名的bean return new String[] { "com.levi.spring.annotations.levi06import.Person"}; } } |
@Configuration @Import(value = {Teacher.class,LeviImportSelector.class,LeviImportBeanDefinitionRegistrar.class,LeviFactoryBean.class}) public class MainConfig {
/** * 容器注册组件的方式: * 1、@Bean:导入类或包到IOC容器中 * 2、包扫描+组件的标注注解,一般针对自己写的类,@ComponentScan、@Controller、@Service、@Repository、@Componet * 3、@Import:导入类或包到IOC容器中,bean的id为类名,主要是@Bean比较简单 * ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组 * ImportBeanDefinitionRegistrar:实现ImportBeanDefinitionRegistrar接口即可。 * 4、使用Spring提供的FactoryBean(工厂bean)进行注册 * BeanFactory是直接从IOC中获取实例化后的实例 * FactoryBean是可以自定义Bean构建时这个过程加入自定义的内容 */ @Bean public Student student() { return new Student(); }
@Bean("studentT") public Student studentT() { return new Student(); }
public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Student student = (Student) applicationContext.getBean("student"); System.out.println(student);
Student student2 = (Student) applicationContext.getBean("studentT"); System.out.println(student2);
//打印所有定义的类 for (String name : applicationContext.getBeanDefinitionNames()) { System.out.println(name); } } } |
@Component public class Teacher implements InitializingBean,DisposableBean {
public Teacher() { System.out.println("Teacher(ID) - 构造器................"); }
public void afterPropertiesSet() throws Exception { System.out.println("Teacher(ID) - bean属性复制和初始化完成时调用"); }
public void destroy() throws Exception { System.out.println("Teacher(ID) - destroy........"); } } |
@Component public class Person {
public Person() { System.out.println("Person JSR250 - 构造器................"); }
@PostConstruct public void afterPropertiesSet() { System.out.println("Person JSR250 - bean属性复制和初始化完成时调用"); }
@PreDestroy public void destroy() { System.out.println("Person JSR250 - destroy........"); } } |
@Component public class Girl implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //返回传进来的对象,在初始化之前调用进行处理工作 System.out.println("Girl-Before:" + bean + " - " + beanName); return bean; }
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("Girl-After:" + bean + " - " + beanName); return bean; } } |
/** * ApplicationContextAware:获取到Spring的上下文 */ @Component public class Boy implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Boy() { System.out.println("Boy 构造器................"); }
@PostConstruct public void afterPropertiesSet() { System.out.println("Boy bean属性复制和初始化完成时调用"); }
@PreDestroy public void destroy() { System.out.println("Boy destroy........"); }
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } } |
@Configuration @ComponentScan(value = "com.levi.spring.annotations.levi07initdestoryway") public class MainConfig {
/** * 定义和销毁的方式: * 1、@Bean注解定义初始化和销毁的方法 * 2、实现InitializingBean接口的afterPropertiesSet()方法,但BeanFactory创建好对象,而且把Bean所有属性 * 都设置好了之后,会调用这个方法,相当于初始化方法。 * 实现DisposableBean的destroy()方法,当Bean销毁时,会把单实例Bean进行销毁。 * 3、根据JSR250规则定义的Java规范的两个注解来实现。 * @PostConstruct:在Bean创建完成,而且属于复制完成后进行初始化,属于JDK规范的注解。 * @PreDestroy:在Bean被移除之前进行通知,在容器销毁之前进行清理工作。 * JSR250是JDK提供的统一规范。 * 4、使用BeanPostProcessor控制Bean的生命周期,这种接近源码 */ @Bean(initMethod = "init",destroyMethod = "destroy") public Student student() { return new Student(); }
public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Student student = (Student) applicationContext.getBean("student"); System.out.println(student);
applicationContext.close(); } } |
AnnotationConfigApplicationContext:
public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Student student = (Student) applicationContext.getBean("student"); System.out.println(student);
applicationContext.close(); } |
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { this(); register(annotatedClasses); refresh(); } |
516行:refresh()
550行:finishBeanFactoryInitialization(beanFactory);
869行:beanFactory.preInstantiateSingletons();
740行:if (isFactoryBean(beanName)) à FactoryBean的定制化作用
760行:getBean(beanName);
199行:doGetBean(name, null, null, false); à (debug)246行
317行:createBean(beanName, mbd, args);
501行:doCreateBean(beanName, mbdToUse, args);
541行:createBeanInstance(beanName, mbd, args); à 完成bean的创建
550行:synchronized (mbd.postProcessingLock) à 后置处理程序
553行:applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
578行:populateBean(beanName, mbd, instanceWrapper); à 属性赋值
579行:initializeBean(beanName, exposedObject, mbd); à Bean初始化,并包括前后置方法的处理 {
1069行:wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); à
1702行:invokeInitMethods(beanName, wrappedBean, mbd); à 初始化方法
1710行:wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
1、结合之前的Bean生命周期的源码,在debug中可以看到是多了几个方法。
2、会判断是否实现了ApplicationContextAware接口,是就会调用invokeAwareInterfaces注入值。
@Override @Nullable public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null;
if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); }
if (acc != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareInterfaces(bean); return null; }, acc); } else { invokeAwareInterfaces(bean); }
return bean; } |
3、其他的前置、后置处理器都是一样的原理的,虽然是使用注解,但是背后原理是一样的。
总结:把Spring底层的组件可以注入到自定义的bean中,ApplicationContextAware是利用ApplicationContextAwareProcessor来处理的,其他的XXXAware也是类似的,都有相关的Processor来处理,其实就是后置处理器来处理。
public class Girl {
/** * 直接复制 */ @Value("Aimi") private String name;
/** * EL表达式 */ @Value("#{10 - 1}") private int age;
/** * 读取配置文件,如果读取不到这个配置,默认为abc */ @Value("${girl.desc:abc}") private String desc;
@Override public String toString() { return "Girl [name=" + name + ", age=" + age + ", desc=" + desc + "]"; } } |
@Configuration public class MainConfig {
@Bean public Girl girl() { return new Girl(); }
public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); Girl girl = (Girl) applicationContext.getBean("girl"); System.out.println(girl); } } |
@Repository public class LeviDao {
private String name = "A";
public LeviDao() { super(); }
public LeviDao(String name) { super(); this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } } |
@Service public class LeviService {
@Qualifier("leviDao") //寻找优先级最高的 @Autowired // @Resource //不支持Primary、不支持Autowired=false // @Inject //在不使用Spring的情况下,可以使用,不支持Autowired=false private LeviDao leviDao;
public void test() { System.out.println("LeviService:" + leviDao.getName()); } } |
@Controller public class LeviController {
@Autowired private LeviService leviService;
} |
@Configuration @ComponentScan(value = "com.levi.spring.annotations.levi09automatically") public class MainConfig {
/** * 自动装配:Spring利用依赖注入,完成对IOC容器中的各个组件的依赖关系赋值。 * @Primary:标注注入IOC的类对象作为自动装配的首选,即优先级最高。如果在@Bean注入对象中,加入这个就说明了这个注入的优先级最高, * 那么@Autowired的优先级不在是优先限定类名了。 * @Autowired:同一个类多个名称,默认优先限定类名,支持required=false,支持@Primary * @Resource:效果和Autowired一样可以装配bean。1、不支持@Primary。2、不支持required=false的功能,即IOC容器中找不到会报错 * @Quialifar:指定ID,始终读取优先级最高的,相对于@Primary来说,@Primary减少了冗余,不用每次读取都指定 * @Inject:可以完成bean装配,这个是需要额外引入第三方的包javax.inject,功能和@Autowired差不多,支持@Primary,只是没有required=false,在没有用Spring框架时,可以用这个。 * * @Component:是一个通用的注解,可以将java类标记为bean,可以是任何Spring管理组件的通用构造型。 * 而@Repository、@Service、@Controller都是@Component的扩展,从源码中可以看得出来。 * @Repository:源码依然是指向@Component,但是是标注在持久层的注解,具有将数据库操作抛出的原生异常翻译成Spring的持久层异常的功能。 * @Service:源码依然是指向@Component,是业务逻辑层的注解,只是标注该类位于业务逻辑层,不会对@Component注解提供任何其他行为。 * @Controller:源码依然是指向@Component,是SpringMVC的注解,具有将请求转发、重定向的功能。 * * 如果IOC容器存在两个ID相同的Bean?会报错 * bean组件优先级?默认优先限定名 * 如何指定装配组件ID进行加载?@Qualifiar * 容器加载不存在的bean会出现什么问题?@Autowired可以用required=false * -@Primary注解bean首选如何使用?在注入的类的中位置加上这个@Primary注解 */
//优先使用 @Primary @Bean public LeviDao leviDao2() { return new LeviDao("B"); }
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
LeviService leviService = annotationConfigApplicationContext.getBean(LeviService.class); leviService.test();
System.out.println(annotationConfigApplicationContext.getBean(LeviDao.class).getName()); annotationConfigApplicationContext.close();
} } |
@Autowired的源码中可以看到用于构造器,用于方法。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired {
/** * Declares whether the annotated dependency is required. * <p>Defaults to {@code true}. */ boolean required() default true;
} |
@Component public class Teacher {
public Teacher() { System.out.println("。。。C。。。Teacher。。。"); }
} |
@Component public class Person {
private Teacher teacher;
@Autowired public Person(Teacher teacher) { System.out.println("。。。C。。。Person。。。" + teacher); }
@Autowired public void setTheacher(Teacher teacher) { this.teacher = teacher; }
public Teacher getTheacher() { System.out.println("。。。M。。。Person。。。" + teacher); return this.teacher; }
} |
@Configuration @ComponentScan(value = "com.levi.spring.annotations.levi09automatically") public class MainConfig {
//优先使用 @Primary @Bean public LeviDao leviDao2() { return new LeviDao("B"); }
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
//测试@Autowired构造器注入,查看对象地址是否是同一个即可 Teacher teacher = annotationConfigApplicationContext.getBean(Teacher.class); System.out.println(teacher);
//测试@Autowired方法注入,查看对象地址是否是同一个即可 Person person = annotationConfigApplicationContext.getBean(Person.class); System.out.println(person.getTheacher());
annotationConfigApplicationContext.close(); } } |
转载地址:http://wqmxi.baihongyu.com/