Spring笔记(一)

说明

有段时间看Spring源码,做的一些笔记,防止丢失,放了上来。
比较琐碎,见谅。

流程相关

常见类名含义

BeanDefinitionReader (从xml或者注解中读取Bean的定义信息)

BeanFactory(工厂)

FactoryBean(拓展的接口,可以创建和管理BeanFactory中的Bean)

ApplicationContextAware(ApplicationContextAware 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法。 用户可以在这个方法中获取上下文环境)

Aware 在应用程序中,想要使用Spring的组件,可以实现这个接口,Spring会通过回调式的方法,把功能注入进去。

populateBean 表示给Bean属性赋值

BeanPostProcessor:bean后置处理器,bean创建对象初始化后进行拦截工作的。

BeanFactoryPostProcessor:beanFactory的后置处理器;在BeanFactory标准初始化之后调用;所有的bean定义已经加载到beanFactory,但是bean的实例还未创建。

BeanDefinitionRegistryPostProcessor 可以修改bean的定义信息,在bean定义信息已经被加载,但是还没实例化的时候生效

BeanDefinitionRegistry Bean定义信息的保存中心,BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个Bean定义信息创建bean实例

RootBeanDefinition 用来自定义bean的定义信息吗,也可以用BeanDefinitionBuilder来构建BeanDefinitionBuilder.rootBeanDefinition( class)

ApplicationListener 用来监听Spring容器事件,ContextRefreshedEvent用来监听刷新的事件,ContextCloesedEvent用来监听容器关闭事件。

refresh流程

		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//预处理
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//创建一个工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//初始化工厂
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				//空方法,未实现
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//执行BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				//注册BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				//初始化,国际化相关的组件
				initMessageSource();

				// Initialize event multicaster for this context.
				//初始化事件派发器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				//未实现,留给子类的
				onRefresh();

				// Check for listener beans and register them.
				//将容器里面所有ApplicationListener注册进来,并且添加到事件派发器中
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//BeanFactory初始化剩下来的bean
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				//完成BeanFactory的创建
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}

prepareRefresh

刷新前的预处理

prepareBeanFactory

给beanFactory设置参数,做一些初始化工作。

注解相关

1、@Scope

多实例

多实例情况下,ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用,并且创建。

@Scope(scopeName = "prototype")

单实例

启动后,就把对象放到容器中,获取的时候通过map.get获取

@Scope(scopeName = "singleton")

还可以为 request(同一个请求创建一个实例), session(同一个session创建一个实例)

2、@lazy

懒加载,针对于单例模式。添加注解后,对象不会一开始就放在容器内,等第一次获取的时候才回去把他放进容器里。

3、@Conditional

满足条件则生效

    @Bean
    @Conditional(WindowsConditional.class)
    public UserInfo getUserInfo() {
        return new UserInfo("小明", 123);
    }

    @Bean
    @Conditional(LinuxConditional.class)
    public UserInfo getUserInfo2() {
        return new UserInfo("小李", 123);
    }

自定义条件

public class WindowsConditional implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        return "Windows 10".equals(environment.getProperty("os.name"));
    }
}

4、添加组件

@Bean

向容器中添加组件的一种方式,通常加在第三方包上。

而@Componet 、@Service、@Autowired这些都是加在方法上。

@Import

也是一种导入组件的方法。

可以直接加类名,也可以自定义一个Bean定义类

@Import(User.class)

//@ComponentScan(basePackages = {"com.dayrain"}, includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})})
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class BeanConfig {

    @Bean
    @Conditional(WindowsConditional.class)
    public UserInfo getUserInfo() {
        return new UserInfo("小明", 123);
    }

    @Bean
    @Conditional(LinuxConditional.class)
    public UserInfo getUserInfo2() {
        return new UserInfo("小李", 123);
    }
}

Bean定义注册类

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Red.class);
        registry.registerBeanDefinition("red", rootBeanDefinition);
    }
}

FactoryBean

FactoryBean也是拓展容器(向容器内部添加Bean)的一种方法。

具体怎么用呢?

我先定义一个类

public class Color {
}

想通过FactoryBean来把他添加进容器中。所以先定义一个 ColorFactoryBean

public class ColorFactoryBean implements FactoryBean<Color> {
    @Override
    public Color getObject() throws Exception {
        return new Color();
    }

    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    //是否是单例
    @Override
    public boolean isSingleton() {
        return true;
    }
}

注册FactoryBean

@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class BeanConfig {

    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
}

测试

public class Main2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext =  new AnnotationConfigApplicationContext(BeanConfig.class);
        Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
        System.out.println(colorFactoryBean.getClass());
    }
}

结果

class com.dayrain.factorybean.Color

虽然@Bean加在FactoryBean上,但实际上ioc容器会调用factoryBean的getObject方法,获取真正需要注入的对象。

5、生命周期

这里的生命周期指的是自定义bean的创建和销毁

方式一:Bean注解

public class Fish {

    public Fish() {
        System.out.println("买了一条鱼");
    }

    public void init() {
        System.out.println("烹饪");
    }

    public void eat(){
        System.out.println("吃了");
    }
}
@Configuration
public class FishConfig {

    @Bean(initMethod = "init", destroyMethod = "eat")
    public Fish fish(){
        return new Fish();
    }
}
public class FishMain {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(FishConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

方式二:实现预制接口

public class Bird implements InitializingBean, DisposableBean {

    public Bird() {
        System.out.println("出生了");
    }

    @Override
    public void destroy(){
        System.out.println("走了");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("来了");
    }
}

方式三:@PostConstruct和@PreDestory

public class Dog {
    public Dog(){
        System.out.println("创建");
    }

    @PostConstruct
    public void init(){
        System.out.println("初始化");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("销毁");
    }
}

public class DogMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(DogConfig.class);
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

方式四:BeanPostProcessor

需要实现接口

BeanPostProcessor

postProcessBeforeInitialization 初始化执行之前

postProcessAfterInitialization 初始化执行之后

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization执行了");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization执行了");
        return bean;
    }
}

但是这么做是对容器内所有的bean都生效。

如果返回值为null,表示后面的BeanPostProcessor都不会执行了

7、@Value

给Bean赋值,加在Bean的属性上

可以是常规值,表达式值( #{} ),引用外部文件值( ${} )

8、@Primary

比如容器中可能会出现多个UserInfo,如果其中一个加上来@Primary,

则Spring在进行自动装配的时候,会优先注入这个Bean。

@Autowired
UserInfo userinfo;

@Resource是不支持@Primary的

9、@Profile

@Profile:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;

/**
 * Profile:
 * 		Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
 * 
 * 开发环境develop、测试环境test、生产环境master
 * 数据源:(/dev) (/test) (/master)
 *
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
 * 
 * 1) 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
 * 2) 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
 * 
 */
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
	
	@Value("${db.user}")
	private String user;
	
	private String driverClass;
	
	@Profile("default")
	@Bean("test")
	public DataSource testDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	@Profile("dev")
	@Bean("dev")
	public DataSource devDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	@Profile("master")
	@Bean("master")
	public DataSource masterDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(password);
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
 
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		String driverClass = resolver.resolveStringValue("${db.driverClass}");
		this.driverClass = driverClass;
	}
 
}


public class IOCTestProfile {
	//1. 使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
	//2. 使用代码的方式激活某种环境;
	@Test
	public void test01() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
		//1. 创建一个applicationContext
		//2. 设置需要激活的环境
		applicationContext.getEnvironment().setActiveProfiles("dev","master");
		//3. 注册主配置类
		applicationContext.register(MainConfigOfProfile.class);
		//4. 启动刷新容器
		applicationContext.refresh();
		
		String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
		System.out.println(Arrays.toString(beanNamesForType));
		
		applicationContext.close();
	}
 
 
        @Test
	public void test02() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
		
		String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
		System.out.println(Arrays.toString(beanNamesForType));
		
		applicationContext.close();
	}
}

10、@EventListener

可以监听事件,使用案例

@Component
public class UserService {

    @EventListener(classes = {ApplicationEvent.class})
    public void listen(ApplicationEvent event) {
        System.out.println("UserService.....监听到事件");
    }
}

AOP

AnnotationAwareAspectJAutoProxyCreator

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值