【spring源码】一、注解驱动开发

Spring注解详解 一、Spring注解驱动开发入门 spring在2.5版本引入了注解配置的支持,同时从Spring 3版本开始,Spring JavaConfig项目提供的许多特性成为核心Spring框架的一部分。因此,可以使用Java而不是XML文件来定义应用程序类外部的bean。在这里面官方文档为我们提供了四个基本注解@Configuration,@Bean,@Import,@DependsOn 用于注解驱动的注解 1.1、@Configuration 1.1.1、源码 @Target(Ele 阅读详情

原来xml方式

img

https://www.jianshu.com/p/2692bf784976

BeanFactory 调用 initializeBean , initializeBean 调用所有的 BeanPostProcessor , BeanPostProcessor 调用 postProcessBeforeInitialization + postProcessAfterInitialization

注解驱动

Maven:spring-context

配置类

@Configuration

思路是用一个java类代替原来的xml文件

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
//用ComponentScans可以指定多个扫描规则,也可以直接写ComponentScan
@ComponentScans(//相当于原来xml配置的包扫描//带s
    value = {
        @ComponentScan(value="com.atguigu",
                       includeFilters = {
                           /*	
                            @Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
                            @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),*/
                           @Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})//自定义扫描规则
                       },
                       useDefaultFilters = false
                      )	
    }
)
//@ComponentScan  value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则
public class MainConfig {

    //给容器中注册一个Bean;也可以在配置类上@Import({.class})
    //类型为返回值的类型,id默认是用方法名作为id
    @Bean("person")//id//还有@Scope()//@Lazy//
    //@Conditional({})//@Conditional(LinuxCondition.class)这个类实现了Condition接口,具体可以去代码中看,实现了一个matches方法,返回bool//context.getEnvironment()获取操作环境,然后environment.getProperty("os.name")获取系统
    public Person person01(){
        return new Person("lisi", 20);
    }
}
public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    }
@ComponentScan【bean注册方法1】

是扫描配置类外加了如下这些注解的类:@Component、@Service、@Repository、@Controller

加了这些注解后,对应的类就会注册一个bean实例,为了让配置类知道去找到你注解了类,需要在配置类上用@ComponentScans指明去哪里扫描。

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类

@ComponentScans(
    value = {
        @ComponentScan(value="com.atguigu",includeFilters = {
            /*						@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
						@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),*/
            @Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
        },useDefaultFilters = false)	
    }
)
//@ComponentScan  value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则
public class MainConfig {
    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    @Bean("person")
    public Person person01(){
        return new Person("lisi", 20);
    }
}
@Bean【bean注册方法2】

在配置类中直接在一个自定义方法上注解@Bean,返回的对象就会注册到容器中。

略嫌麻烦,常用@Import

//默认是单实例的
/**
	 * @Scope:调整作用域
	 * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
	 * 					每次获取的时候才会调用方法创建对象;
	 * singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。
	 * 			以后每次获取就是直接从容器(map.get())中拿,
	 * request:同一次请求创建一个实例,需要在web环境
	 * session:同一个session创建一个实例,需要在web环境
	 * 
	 * 懒加载:
	 * 		单实例bean:默认在容器启动的时候创建对象;
	 * 		懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
	 */
//	@Scope("prototype")
@Lazy
@Bean("person")//@Bean(initMethod="init",destroyMethod="detory")//对应的init方法也在Person类里
//还有其他方法看生命周期部分
public Person person(){
    System.out.println("给容器中添加Person....");
    return new Person("张三", 25);
}
@Conditional

在@Bean的同个方法上注解@Conditional({自定义.class}): 按照一定的条件进行判断,满足条件给容器中注册bean。

注解里可以传入一个自定义的class对象,

/**
	 * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
	 * 如果系统是windows,给容器中注册("bill")
	 * 如果是linux系统,给容器中注册("linus")
	 */
@Conditional(LinuxCondition.class)//linux环境下才注册这个bean//自定义的class,返回bool
@Bean("linus")
public Person person02(){
    return new Person("linus", 48);
}
//---------package com.atguigu.condition;-----------------------------------
//判断是否linux系统
public class LinuxCondition implements Condition {

	/**
	 * ConditionContext:判断条件能使用的上下文(环境)
	 * AnnotatedTypeMetadata:注释信息
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO是否linux系统
		//1、能获取到ioc使用的beanfactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//2、获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//3、获取当前环境信息
		Environment environment = context.getEnvironment();
		//4、获取到bean定义的注册类
		BeanDefinitionRegistry registry = context.getRegistry();
		
		String property = environment.getProperty("os.name");
		
		//可以判断容器中的bean定义情况,也可以给容器中注册bean
		boolean definition = registry.containsBeanDefinition("person");
		if(property.contains("linux")){
			return true;
		}
		
		return false;
	}
}
@Import【bean注册方法3】

@Import标注在config注册类上,在注册ac的时候就会自动把@Import(Dog.class)里标注的类实例化注册到容器中

  • @Import(要导入到容器中的组件.class);容器中就会自动注册这个组件,id默认是全类名
  • @Import(new ImportSelector(){@Override}:返回需要导入的组件的全类名数组;(事务源码中会用到)
  • @Import(new ImportBeanDefinitionRegistrar(,){@Override}:手动注册bean定义到容器中(aop源码中会使用)
在Configuration类上标注:;
@Import({Color.class,Red.class,
         MyImportSelector.class,//返回需要导入的组件的全类名数组;实现ImportSelector接口,函数式接口返回数组即可。可以返回一个空数组,但不要返回一个null
         MyImportBeanDefinitionRegistrar.class}//手动注册bean到容器中。实现ImportBeanDefinitionRegistrar接口,一个void方法,
       )
//返回需要导入的组件的全类名数组
public class MyImportSelector implements ImportSelector {
	//返回值,就是到导入到容器中的组件全类名
	//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
		//importingClassMetadata
		//方法不要返回null值
		return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
	}
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:BeanDefinition注册类;
把所有需要添加到容器中的bean;调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//逻辑:如果有红蓝的bean,就可以生成彩虹bean
		boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
		boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
		if(definition && definition2){
			//指定Bean定义信息;(Bean的类型,Bean。。。)
			RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
			//注册一个Bean定义,指定bean名,但还没有创建bean,getBean后才创建
			registry.registerBeanDefinition("rainBow", beanDefinition);
		}
	}
}
@FactoryBean【bean注册方法4】
给容器中注册组件;
1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
2)、@Bean[导入的第三方包里面的组件]
4)、使用Spring提供的 FactoryBean(工厂Bean);
	1)、默认获取到的是工厂bean调用getObject创建的对象
	2)、要获取工厂Bean本身,我们需要给id前面加一个&
		&colorFactoryBean
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {

    //返回一个Color对象,这个对象会添加到容器中
    @Override
    public Color getObject() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("ColorFactoryBean...getObject...");
        return new Color();
    }

    @Override
    public Class<?> getObjectType() {
        // TODO Auto-generated method stub
        return Color.class;
    }

    //是单例?
    //true:这个bean是单实例,在容器中保存一份
    //false:多实例,每次获取都会创建一个新的bean;
    @Override
    public boolean isSingleton() {
        // TODO Auto-generated method stub
        return false;
    }
}

//------在config配置类中----这是个工厂bean------
@Bean
public ColorFactoryBean colorFactoryBean(){
    return new ColorFactoryBean();//注册的不是ColorFactoryBean,而是Color
}

组件注册

//介绍一个方法:
String[]  =ac.getBeanNamesForType(Person.class);

生命周期

1)指定初始化和销毁方法;

  •  通过@Bean指定init-method和destroy-method;
    

2)通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);

3)可以使用JSR250;在bean类中的方法上注解

  •  @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
    
  •  @PreDestroy:在容器销毁bean之前通知我们进行清理工作
    

4)实现接口BeanPostProcessor,并在该类上@Component

  •  在bean初始化前后进行一些处理工作;
    
  •   postProcessBeforeInitialization(bean,beanName)方法:在初始化之前工作。通过指定形参来确定操作的bean。每个bean前后都会执行
    
  •  postProcessAfterInitialization():在初始化之后工作
    
package com.atguigu.config;

import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import com.atguigu.bean.Car;

/**
 * bean的生命周期:
 * 		bean创建---初始化----销毁的过程
 * 容器管理bean的生命周期;
 * 我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
 * 
 * 构造(对象创建)
 * 		单实例:在容器启动的时候创建对象
 * 		多实例:在每次获取的时候创建对象
 * 
 * BeanPostProcessor.postProcessBeforeInitialization
 * 初始化:
 * 		对象创建完成,并赋值好,调用初始化方法。。。
 * BeanPostProcessor.postProcessAfterInitialization
 * 销毁:
 * 		单实例:容器关闭的时候
 * 		多实例:容器不会管理这个bean;容器不会调用销毁方法;
 * 
 * 
 * 遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
 * 一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
 * 
 * BeanPostProcessor原理
 * populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
 * initializeBean{
      applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
      invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
      applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 *}
 * 
 * Spring底层对 BeanPostProcessor 的使用;
 * 		bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
 */
//配置类
@ComponentScan("com.atguigu.bean")
@Configuration
public class MainConfigOfLifeCycle {
	
	//@Scope("prototype")
	@Bean(initMethod="init",destroyMethod="detory")
	public Car car(){
		return new Car();
	}
}
@Component
public class Cat implements InitializingBean,DisposableBean {//实现初始化和销毁接口
	
	public Cat(){
		System.out.println("cat constructor...");
	}

	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...destroy...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...afterPropertiesSet...");
	}
}
@Component
public class Dog implements ApplicationContextAware {//实现ApplicationContextAware就自动调用setApplicationContext(ac)
	
	//@Autowired
	private ApplicationContext applicationContext;
	
	public Dog(){
		System.out.println("dog constructor...");
	}
	
	//对象创建并赋值之后调用
	@PostConstruct
	public void init(){
		System.out.println("Dog....@PostConstruct...");
	}
	
	//容器移除对象之前
	@PreDestroy
	public void detory(){
		System.out.println("Dog....@PreDestroy...");
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// TODO Auto-generated method stub
		this.applicationContext = applicationContext;
	}
}

后置处理器

实现接口BeanPostProcessor,并且在该类上@Component

  •  在bean初始化前后进行一些处理工作;
    
  •   postProcessBeforeInitialization(bean,beanName)方法:在初始化之前工作。通过指定形参来确定操作的bean。每个bean前后都会执行
    
  •  postProcessAfterInitialization():在初始化之后工作
    

image-20200430185548444

new AppContext的时候就调用后置处理器了,倒数第二个调用refresh(),

一层一层的调用关系:
    ================
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
==================
    refresh();
=============

    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);//初始化所有剩下的非懒加载的单例
============
    beanFactory.preInstantiateSingletons();
============
    this.getBean(beanName);
===========
    public Object getBean(String name) throws BeansException {
    	return this.doGetBean(name, (Class)null, (Object[])null, false);
	}
===============
    sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
        public Object getObject() throws BeansException {
            try {
                return AbstractBeanFactory.this.createBean(beanName, mbd, args);
            } catch (BeansException var2) {
                AbstractBeanFactory.this.destroySingleton(beanName);
                throw var2;
            }
        }
    });
=================
    singletonObject = singletonFactory.getObject();
newSingleton = true;
====================
    return AbstractBeanFactory.this.createBean(beanName, mbd, args);
====================
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {//calculator时为空
        return bean;//如果生成了代理对象,就直接返回了。没有生成则继续往下执行
    }
    beanInstance = this.doCreateBean(beanName, mbdToUse, args);
===================
    //创建实例
    //属性赋值
    this.populateBean(beanName, mbd, instanceWrapper);//给bean进行属性赋值setter getter
	//初始化
    if (exposedObject != null) {
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    }
====================
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);//卡在这//
        //打开是:getBeanPostProcessors().iterator();//循环遍历得到所有beanProcessor,挨个执行beanProcessor.postProcessBeforeInitialization()
        /*
           do {
            if (!var4.hasNext()) {
                return result;
            }
            BeanPostProcessor beanProcessor = (BeanPostProcessor)var4.next();
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        } while(result != null);
           */
    }

try {
    this.invokeInitMethods(beanName, wrappedBean, mbd);//执行bean初始化方法
} catch (Throwable var6) {
    throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}

if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//后置
}
===================
    result = beanProcessor.postProcessBeforeInitialization(result, beanName);
@Component//下面全部的bean都会经过
public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
		return bean;
	}
}

ApplicationContextAwareProcessor帮组件注入IoC容器,我们用的是implements ApplicationContextAware,会自动注入到setApplicationContext()的方法参数中,这个功能就是ApplicationContextAwareProcessor做的,比如她的方法

@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    AccessControlContext acc = null;
    //判断bean实现了Aware接口没有
    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();//把ac传过来
    }
    if (acc != null) {//ac有值
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                invokeAwareInterfaces(bean);//if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);、//调用set方法
			}
                return null;
            }
        }, acc);
    }else

属性赋值@Value

在bean类中–属性上使用@Value("")赋值,相当于原来的<property>。字符串内容可以是

  • 基本数值
  • 可以写SpEL; #{}
  • 可以写${};在配置类上注解@PropertySource(value="classpath:/person.properties")。然后在bean类中@Value("${person.nickName}")去除值
public class Person {
	
	//使用@Value赋值;
	//1、基本数值
	//2、可以写SpEL; #{}
	//3、可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)
	
	@Value("张三")
	private String name;
	@Value("#{20-2}")
	private Integer age;
	
	@Value("${person.nickName}")//去除配置文件/环境变量中的值//需要在配置类上加上注解@PropertySource("classpath:/dbconfig.properties")
	private String nickName;
	getter...setter...;
}

自动装配

@Autowired+@Qualifier+@Primary

spring支持3种自动装配

  • @Qualifier("bookDao"):放在空成员上,指定要装配的bean id

  • @Autowired(required=false);:放在空成员上

  • @Primary(""):下面两个是放在bean上。指定这是一个首选的bean,放在@Bean或@Component周围

java的自动装配:

  • @Resource:可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
  • @Inject

先按照类型去查找,有多个时候再将属性的名称作为组件的id去查找。或者在属性上使用@Qualifier("")指定id。找不到bean会报错,可以通过@Autowired(required=“false”)指定该属性可以不装配。

  • 还可以@Primary让spring装配首选的bean,
  • spring还支持使用@Resource(JSR250)和@Inject(JSR330)。java规范的注解。@Resource(name="")默认是通过组件名称装配的。没有能支持@Primary功能没有支持@Autowired(required=false)。@Inject需要导入依赖javax.inject,也没有required=false功能。@Autowired是spring定义的。@Resource和@Inject是java的规范。区别在于后面两个没有required=false
/**
 * 自动装配;
 * 		Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;
 * 
 * 1)、@Autowired:自动注入:
 * 		1)、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值
 * 		2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找。ac.getBean("bookDao")
 * 		3)、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
 * 		4)、自动装配默认一定要将属性赋值好,没有就会报错;
 * 			可以使用@Autowired(required=false);
 * 		5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
 * 				也可以继续使用@Qualifier指定需要装配的bean的名字
 * 
 * 2)、Spring还支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解]
 * 		@Resource:
 * 			可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
 * 			没有能支持@Primary功能,没有支持@Autowired(reqiured=false);
 * 		@Inject:
 * 			需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;
 *  @Autowired:Spring定义的; @Resource、@Inject都是java规范
 * 	
 * AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能;		
 * 
 * 3)、 @Autowired:构造器,参数,方法,属性;都是从容器中获取参数组件的值
 * 		1)、[标注在方法位置]:标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值;//方法使用的参数,自定义类型的值从ioc容器中获取
 		@Bean+方法参数;参数从容器中获取;默认不写@Autowired效果是一样的;都能自动装配	//
	
 * 		2)、[标在构造器上]:构造器用的组件也是从环境中自动获取。但是如果组件只有一个有参构造器(没有无参构造器),这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取,一个@Autowired都不需要加
 * 		3)、放在方法的参数位置:效果同理。同样还可以标在@Bean修饰的参数上
 *  
 * 4)、自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);
 * 		只需要自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的set方法注入相关组件;Aware;
 * 		把Spring底层一些组件注入到自定义的Bean中;
 * 		xxxAware:功能使用xxxProcessor;
 * 			ApplicationContextAware==》ApplicationContextAwareProcessor;
 */
@Service
public class BookService {
	
	//@Qualifier("bookDao")
	//@Autowired(required=false)
	//@Resource(name="bookDao2")//java规范
	@Inject//JAVA规范
	private BookDao bookDao;
	
	public void print(){
		System.out.println(bookDao);
	}

	@Override
	public String toString() {
		return "BookService [bookDao=" + bookDao + "]";
	}
}
Aware

自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware接口中有写。

  •  把Spring底层一些组件注入到自定义的Bean中;比如实现了ApplicationContextAware接口,就会实现了setApplicationContext方法,会自动传入ApplicationContext。还有Bean
    
  •  xxxAware:功能使用xxxProcessor;
    
  •  ApplicationContextAware==》ApplicationContextAwareProcessor;
    
@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
	
	private ApplicationContext applicationContext;

	@Override//无需写Autowired
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("传入的ioc:"+applicationContext);
		this.applicationContext = applicationContext;
	}

	@Override
	public void setBeanName(String name) {
		// TODO Auto-generated method stub
		System.out.println("当前bean的名字:"+name);
	}

	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		// TODO Auto-generated method stub
		String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
		System.out.println("解析的字符串:"+resolveStringValue);
	}
}
@Profile:
  •  Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
    
  •  开发环境、测试环境、生产环境;数据源:(/A)(/B)(/C);
    
  •  @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
    
  •  1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
    
  •  2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
    
  •  3)、没有标注环境标识的bean在,任何环境下都是加载的;
    
/**
 * Profile:
 * 		Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
 * 
 * 开发环境、测试环境、生产环境;
 * 数据源:(/A)(/B)(/C);
 * 在pom.xml中引入c3p0数据源,mysql驱动
 * 
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
 * 
 * 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
 * 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
 * 3)、没有标注环境标识的bean在,任何环境下都是加载的;
 */

@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{

    @Value("${db.user}")
    private String user;
    private StringValueResolver valueResolver;
    private String  driverClass;


    @Bean
    public Yellow yellow(){
        return new Yellow();
    }

    @Profile("test")
    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }


    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Profile("prod")
    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");

        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {//另一种获取环境变量的方法
        // TODO Auto-generated method stub
        this.valueResolver = resolver;
        driverClass = valueResolver.resolveStringValue("${db.driverClass}");
    }

}
-------------------------------------------------
public class IOCTest_Profile {

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


        String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class);
        for (String string : namesForType) {
            System.out.println(string);
        }

        Yellow bean = applicationContext.getBean(Yellow.class);
        System.out.println(bean);
        applicationContext.close();
    }

}

AOP

  • 导包spring-aspects
  • 在配置类上@EnableAspectJAutoProxy

AOP:【动态代理】指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;

1、导入aop模块;Spring AOP:(spring-aspects)

2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)

3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;

  •  通知方法:
    
  •  前置通知(@Before):logStart:在目标方法(div)运行之前运行
    
  •  后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
    
  •  返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
    
  •  异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
    
  •  环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
    

4、给切面类的目标方法标注何时何地运行(通知注解);

5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;

6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)

7、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】。在Spring中很多的 @EnableXXX;

/**
 * 三步:
 * 	1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
 * 	2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
 *  3)、开启基于注解的aop模式;@EnableAspectJAutoProxy
 *  
 * AOP原理:【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】
 * 		@EnableAspectJAutoProxy;
 * 1、@EnableAspectJAutoProxy是什么?
 * 		@Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar
 * 			利用AspectJAutoProxyRegistrar自定义给容器中注册bean;BeanDefinetion
 * 			internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
 * 
 * 		给容器中注册一个AnnotationAwareAspectJAutoProxyCreator;
 * 
 * 2、 AnnotationAwareAspectJAutoProxyCreator:
 * 		AnnotationAwareAspectJAutoProxyCreator
 * 			->AspectJAwareAdvisorAutoProxyCreator
 * 				->AbstractAdvisorAutoProxyCreator
 * 					->AbstractAutoProxyCreator
 * 							implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
 * 						关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory
 * 
 * AbstractAutoProxyCreator.setBeanFactory()
 * AbstractAutoProxyCreator.有后置处理器的逻辑;
 * 
 * AbstractAdvisorAutoProxyCreator.setBeanFactory()-》initBeanFactory()
 * 
 * AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
 *
 *
 * 流程:
 * 		①1)、传入配置类,创建ioc容器
 * 		②2)、注册配置类,调用refresh()刷新容器;
 * 		③3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;
 * 			1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
 * 			2)、给容器中加别的BeanPostProcessor
 * 			3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
 * 			4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
 * 			5)、注册没实现优先级接口的BeanPostProcessor;
 * 			6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
 * 				创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
 * 				1)、创建Bean的实例
 * 				2)、populateBean;给bean的各种属性赋值
 * 				3)、initializeBean:初始化bean;
 * 						1)、invokeAwareMethods():处理Aware接口的方法回调
 * 						2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
 * 						3)、invokeInitMethods();执行自定义的初始化方法
 * 						4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
 * 				4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
 * 			7)、把BeanPostProcessor注册到BeanFactory中;
 * 				beanFactory.addBeanPostProcessor(postProcessor);
 * =======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程========
 * 
 * 			AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
 * 		④4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;创建剩下的单实例bean
 * 			1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
 * 				getBean->doGetBean()->getSingleton()->
 * 			2)、创建bean
 * 				【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()】
 * 				1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;只要创建好的Bean都会被缓存起来
 * 				2)、createBean();创建bean;
 * 					AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean的实例
 * 					【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】
 * 					【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】
 * 					1)、resolveBeforeInstantiation(beanName, mbdToUse);希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续
 * 						1)、后置处理器先尝试返回对象;
 * 							bean = applyBeanPostProcessorsBeforeInstantiation():
 * 								拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;
 * 								就执行postProcessBeforeInstantiation
 * 							if (bean != null) {
								bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
							}
 * 
 * 					2)、doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例;和3.6流程一样;
 * 					3)、
 * 			
------------
 * AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】	的作用:
 * 1)、每一个bean创建之前,调用postProcessBeforeInstantiation();
 * 		关心MathCalculator和LogAspect的创建
 * 		1)、判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
 * 		2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,
 * 			或者是否是切面(@Aspect)
 * 		3)、是否需要跳过
 * 			1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】
 * 				每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;
 * 				判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
 * 			2)、永远返回false
 * 
 * 2)、创建对象
 * postProcessAfterInitialization;
 * 		return wrapIfNecessary(bean, beanName, cacheKey);//包装如果需要的情况下
 * 		1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors
 * 			1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
 * 			2、获取到能在bean使用的增强器。
 * 			3、给增强器排序
 * 		2)、保存当前bean在advisedBeans中;
 * 		3)、如果当前bean需要增强,创建当前bean的代理对象;
 * 			1)、获取所有增强器(通知方法)
 * 			2)、保存到proxyFactory
 * 			3)、创建代理对象:Spring自动决定
 * 				JdkDynamicAopProxy(config);jdk动态代理;
 * 				ObjenesisCglibAopProxy(config);cglib的动态代理;
 * 		4)、给容器中返回当前组件使用cglib增强了的代理对象;
 * 		5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
 * 		
 * 	
 * 	3)、目标方法执行	;
 * 		容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
 * 		1)、CglibAopProxy.intercept();拦截目标方法的执行
 * 		2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
 * 			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 * 			1)、List<Object> interceptorList保存所有拦截器 5
 * 				一个默认的ExposeInvocationInterceptor 和 4个增强器;
 * 			2)、遍历所有的增强器,将其转为Interceptor;
 * 				registry.getInterceptors(advisor);
 * 			3)、将增强器转为List<MethodInterceptor>;
 * 				如果是MethodInterceptor,直接加入到集合中
 * 				如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
 * 				转换完成返回MethodInterceptor数组;
 * 
 * 		3)、如果没有拦截器链,直接执行目标方法;
 * 			拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
 * 		4)、如果有拦截器链,把需要执行的目标对象,目标方法,
 * 			拦截器链等信息传入创建一个 CglibMethodInvocation 对象,
 * 			并调用 Object retVal =  mi.proceed();
 * 		5)、拦截器链的触发过程;
 * 			1)、如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
 * 			2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
 * 				拦截器链的机制,保证通知方法与目标方法的执行顺序;
 * 		
 * 	总结:
 * 		1)、  @EnableAspectJAutoProxy 开启AOP功能
 * 		2)、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
 * 		3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
 * 		4)、容器的创建流程:
 * 			1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
 * 			2)、finishBeanFactoryInitialization()初始化剩下的单实例bean
 * 				1)、创建业务逻辑组件和切面组件
 * 				2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
 * 				3)、组件创建完之后,判断组件是否需要增强
 * 					是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
 * 		5)、执行目标方法:
 * 			1)、代理对象执行目标方法
 * 			2)、CglibAopProxy.intercept();
 * 				1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
 * 				2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
 * 				3)、效果:
 * 					正常执行:前置通知-》目标方法-》后置通知-》返回通知
 * 					出现异常:前置通知-》目标方法-》后置通知-》异常通知
 */

声明式事务

pom:数据源c3p0 数据库驱动mysql jdbc(简化数据库和事务控制)

配置数据源,JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据

  • 声明式事务:

环境搭建:

  • 1、导入相关依赖:数据源、数据库驱动、Spring-jdbc模块

  • 2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据

  • 3、给方法上标注 @Transactional 表示当前方法是一个事务方法;

  • 4、@EnableTransactionManagement 开启基于注解的事务管理功能;@EnableXXX

  • 5、配置事务管理器来控制事务;

    @Bean
    public PlatformTransactionManager transactionManager()
    
/**
 * 原理:
 * 1)、@EnableTransactionManagement
 * 			利用TransactionManagementConfigurationSelector给容器中会导入组件
 * 			导入两个组件
 * 			AutoProxyRegistrar
 * 			ProxyTransactionManagementConfiguration
 * 2)、AutoProxyRegistrar:
 * 			给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
 * 			InfrastructureAdvisorAutoProxyCreator:?
 * 			利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
 * 
 * 3)、ProxyTransactionManagementConfiguration 做了什么?
 * 			1、给容器中注册事务增强器;
 * 				1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解
 * 				2)、事务拦截器:
 * 					TransactionInterceptor;保存了事务属性信息,事务管理器;
 * 					他是一个 MethodInterceptor;
 * 					在目标方法执行的时候;
 * 						执行拦截器链;
 * 						事务拦截器:
 * 							1)、先获取事务相关的属性
 * 							2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
 * 								最终会从容器中按照类型获取一个PlatformTransactionManager;
 * 							3)、执行目标方法
 * 								如果异常,获取到事务管理器,利用事务管理回滚操作;
 * 								如果正常,利用事务管理器,提交事务
 */
@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
	
	//数据源
	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("123456");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
		return dataSource;
	}
	
	//
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件,不会创建new两个对象
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//注册事务管理器 在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());//事务管理器管理事务源
	}
}
@Repository
public class UserDao {
	@Autowired//自动注入
	private JdbcTemplate jdbcTemplate;
    
	public void insert(){
		String sql = "INSERT INTO `tbl_user`(username,age) VALUES(?,?)";
		String username = UUID.randomUUID().toString().substring(0, 5);
		jdbcTemplate.update(sql, username,19);
	}
}
@Service
public class UserService {
	
	@Autowired
	private UserDao userDao;
	
	@Transactional//配置类上还需要@EnableTranctionManagement//原来是<tx-annotation-driven/>//还需要事务管理器DataSourceTransactionManager
	public void insertUser(){
		userDao.insert();
		//otherDao.other();xxx
		System.out.println("插入完成...");
		int i = 10/0;//出错需要回滚
	}
}
spring注解驱动 spring注解驱动spring注解驱动spring注解驱动spring注解驱动 立即下载

相关推荐

Spring注解驱动开发.xmind

Spring注解驱动开发.xmind,是尚硅谷课堂上的注解开发的文档涉及到很多的注解。以及开发原理。

Spring-----IOC已更新

其实对于SpringIOC这个名字,我们已经很熟悉了。如果有不清楚的可以去访问这位大佬的文章:传送门 我想分享和记录的是我在学习SpringIOC容器中学会的一些方法。Spring注解驱动---因为现在都在提倡使用注解开发,之前基于xml的配置比较复杂和繁琐,因此在现在的开发中为了简化配置文件的书写,慢慢使用注解替换xml。 1.组件注册------@Configuration 使用“@Co...

MonkeyBrothers的博客 425

百度智能云ASR实战:5分钟搞定Unity语音转文字(含完整代码)

本文详细介绍了如何在Unity中集成百度智能云ASR服务,实现高效的语音转文字功能。从环境配置、音频处理到服务端通信,提供完整代码示例和实战优化技巧,帮助开发者快速实现语音交互功能,适用于游戏开发、XR应用等场景。

ujm56789012的博客 215

Spring初始化对象几种自定义实现方式以及执行顺序

Spring初始化对象几种自定义实现方式以及执行顺序

weixin_45058835的博客 1446

智能车竞赛独轮组信标灯系统全解析:从硬件选型到实战调试

本文全面解析了智能车竞赛独轮组信标灯系统的核心原理与实战应用。从硬件架构(灯板、灯罩、控制器)的深度剖析,到红外信号(特别是40kHz调制信号)的接收与解码策略,再到车模的灭灯机构设计与路径规划,提供了从硬件选型到软件调试的全链路指南。文章重点分享了实战调试技巧与常见问题排查方法,旨在帮助参赛队伍深入理解系统,提升车模的识别精度与比赛表现。

e4f5g6h的博客 1124

Seedance 2.5本地部署指南:AI生图与视频生成的完整实践

最近在AI生成内容领域,本地部署方案越来越受到开发者关注。特别是Seedance 2.5的发布,让很多原本依赖云端服务的用户开始转向本地化解决方案。本文将从实际使用角度出发,完整介绍Seedance 2.5的本地部署流程、功能特性对比以及实际应用技巧。 1. Seedance 2.5核心特性解析 1.1 什么是Seedance 2.5 Seedance 2.5是一款开源的AI生图和视频生成工具,支持在本地环境运行,无需联网即可实现高质量的图像和视频生成。相比之前的2.0版本,2.5在生成质量、运行效率和功能

weixin_42566121的博客 1655

Springboot启动初始化数据,执行sql脚本

方法一:配置application.yml文件 纯配置。最方便简洁,是最优选择。 yml文件: spring: datasource: schema: classpath:schema.sql data: classpath:data.sql initialization-mode: always 再在resource目录下添加schema.sql和data....

ssss_cccc的博客 3992

阿里云CDN HTTPS 证书配置流程

可以使用HTTPS方式访问资源,如果浏览器中URL旁边出现锁的HTTPS标识,表示HTTPS安全加速已生效。: 证书配置完成后,需要留意证书过期时间并在证书过期前手动配置新的证书。注意 ⚠️ 一定是需要复制 以下标识之间的内容。如果已在阿里云数字证书管理服务中购买了证书,请选择。,该证书将在阿里云数字证书管理服务中保存。如果使用第三方服务商签发的证书,请选择。第四步,在指定域名的左侧导航栏,单击。第二步,在左侧导航栏,单击。开关,并配置证书相关参数。页面,找到目标域名,单击。中选择已购买的证书。

w风雨无阻w的专栏 2207

Mybatis+Spring整合源码

Mybatis+Spring整合源码解析

qq_41972358的博客 636

antv x6 沿边图标循环动画实现

2.使用transition给边设置动画,利用complte方法实现循环动画。实现效果,如下图,边上存在两个图标,要求图标延边一直循环动画。1.注册一个自定义边,边上定义两个图标,并设置其初始位置。

lingliu0824的博客 3366

微信小程序云开发 - 实现商家转账到零钱(微信企业付款到零钱) V3功能流程及完整实例代码,过微信云开发的云函数实现企业付款到零钱(提供详细示例源码纯云函数实现,证书、密钥、签名等各种常见问题解决方案

企业付款到零钱(微信小程序提现功能,提现到零钱)微信小程序-云函数实现微信企业付款到零钱功能,实现微信商户号中的企业付款到零钱的功能,微信小程序+云开发+商家转账至零钱+微信小程序用户提现,使用云开发环境的云函数实现微信小程序的支付功能,微信小程序实现微信企业付款到零钱功能的流程,V3 V2基于微信云开发的商家转账至零钱,小程序云函数企业付款到零钱功能实现,云开发实现微信商户支付企业付款到零钱功能,不用服务器纯云函数实现,详细示例代码demo教程,API证书错误,转账不到账怎么办,密钥生成有误,转账失败,有

🏆 前端领域优质创作者 1万+

bean加载context idea_idea中的javabean使用详解

一、先创建一个web模块(右键项目名)二、选择webapplication三、给所创建的项目部署tomcat点击Edit Configurations点击左上角的+号找到tomcat server ->local->Deployment->右边的+号->artifact->找到刚创建的模块->部署成功点击Apply在Src下创建一个Bean包->Bean包...

weixin_39689622的博客 374

Cesium 实战 04 - 标绘功能系列之画点(draw point)

Cesium 实战 - 标绘功能之画点(draw point)。

非科班Java出身GISer的博客 1082

Spring注解驱动开发(部分源码原理)笔记 (一) 组件的注册

Spring的容器类 xmlBean配置容器类: ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); 注解Bean配置容器类(): ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.i9577.config"); ApplicationContext app

酒舞叮叮的博客 285

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Spring注解驱动开发第41讲——Spring IOC容器创建源码解析(一)之BeanFactory的创建以及预准备工作

写在前面 在前面,我们已经学会了怎样来使用ApplicationListener,也研究了一下其内部原理。而从这一讲开始,我们就要结合我们以前学过的所有内容,来梳理一下Spring整个容器的创建以及初始化过程。我是希望通过对Spring源码的整个分析,令大家对Spring内部的工作原理以及运行机制能有一个更深刻的理解。 接下来,我们来分析并详细记录一下Spring容器的创建以及初始化过程。 BeanFactory的创建以及预准备工作 我们先来看一下如下的一个单元测试类(例如IOCTest_Ext)。 pac

李阿昀的博客 2790

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Spring bean的生命周期

生命周期 生命周期及对其控制 bean生命周期分为7个阶段 创建实例 属性赋值 初始化前 初始化 初始化后 使用 销毁 对于单实例bean,容器创建好了,bean也就创建好了,容器关闭了,bean也调用destroy方法销毁 对于多实例bean,直到使用才会去创建,容器关闭,也不会调用destroy方法销毁 我们使用@Bean注册组件时,可以使用@Bean(initMethod = “init”, destroyMethod = “destroy”)指定初始化方法名,销毁方法名 如果是使用组件扫描加入

qq_44078893的博客 191

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Spring注解驱动开发第1讲——今天,我们来聊聊关于Spring注解驱动开发的那些事儿!

写在前面 小伙伴们,大家早上好!今天是2020年11月27日,星期五,晴。我起来的好晚,一起来又要开始学习的时候了,昨天看了雷丰阳老师讲授的Spring注解驱动教程的一部分,也就是20个视频,第一个感觉就是老师讲解的好好,甚至有时会进入源码中去看看Spring内部到底是咋个样子的,确实是跟随老师的脚步能学到好多东西,在这里要谢谢雷丰阳老师讲授了这样好的视频,第二个感觉就是学的脑子都快要炸了,由于要学习的知识太多了,而我又是这样一个极笨的人,所以为了避免遗忘昨天学习的知识点,遂特地开了一个新的专栏,记录下学习

李阿昀的博客 1万+

历时三个月,史上最详细的Spring注解驱动开发系列教程终于出炉了,给你全新震撼

写在开头 从2020年11月27日到今天(即2021年3月21日)为止,历时接近三个月,我写的「史上最详细的Spring注解驱动开发系列教程」终于新鲜出炉了!好嗨哟!我实在是太开心了,因为每一篇文章我都花费了大量的时间、精力和心血,一篇文章写下来,少则3、4个小时,多则3、4天,我实在是太难了! 整个系列教程,我是总共分为了五大部分,分别是:IOC容器、AOP切面、声明式事务、扩展原理和web相关。大部分内容都是以实战为主,期间我也适当的讲解了Spring的底层原理和源码相关的知识。尤其是在研究AOP底层原

李阿昀的博客 3万+

Spring注解驱动开发(一)

*** @param metadataReader 读取到当前正在扫描类的信息* @param metadataReaderFactory 可以获取其他任何类的信息*/@Override// 获取当前类注解的信息// 获取当前正在扫描类的信息// 获取当前类的资源信息(类的路径)BeanFactory,以Factory结尾,表示它是一个工厂类(接口),它负责生产和管理bean的一个工厂。在Spring中,

小孔靠得住的博客 1811

Spring注解驱动开发之@Resource

Resource是JSR-250规范定义的标准注解,属于JavaEE标准体系的一部分。与Spring特有的@Autowired注解相比,具有更好的框架通用性。Class<?// 其他属性省略...核心属性说明:name:指定目标Bean的名称type:显式指定Bean类型(用于类型验证)其他企业级特性(如authenticationType、shareable等)场景推荐注解理由需要构造方法注入@Autowired天然支持构造器注入跨框架组件@Resource更好的通用性。

qq_42844685的博客 3514

【Spring注解驱动开发】聊聊Spring注解驱动开发那些事儿!

写在前面 今天,面了一个工作5年的小伙伴,面试结果不理想啊!也不是我说,工作5年了,问多线程的知识:就只知道继承Thread类和实现Runnable接口!问Java集合,竟然说HashMap是线程安全的!问MySQL的MyISAM存储引擎和InnoDB存储引擎的区别,竟然说成是MyISAM存储引擎支持事务,InnoDB不支持!问Spring就只知道IOC和AOP的概念,深一点就不知道了!再问项目。。。哎,算了,不说了! 大家对于设计模式、高并发和Java8新特性,不了解的,就去看我的专栏吧!今天,我们来

冰河的专栏 3728

「Spring注解驱动开发」聊聊Spring注解驱动开发那些事儿

写在前面 今天,面了一个工作5年的小伙伴,面试结果不理想啊!也不是我说,工作5年了,问多线程的知识:就只知道继承Thread类和实现Runnable接口!问Java集合,竟然说HashMap是线程安全的!问MySQL的MyISAM存储引擎和InnoDB存储引擎的区别,竟然说成是MyISAM存储引擎支持事务,InnoDB不支持!问Spring就只知道IOC和AOP的概念,深一点就不知道了!再问项目。。。哎,算了,不说了! 大家对于设计模式、高并发和Java8新特性,不了解的,就去看我的专栏吧!今天,..

Javaesandyou的博客 1517

Spring注解驱动开发

Component@Override// 返回传入的原始bean,或者进行了包装之后的bean@Override// 返回传入的原始bean,或者进行了包装之后的bean中调用为bean填充属性,然后调用开始进行bean的初始化以及bean初始化的前后处理。调用方法:该方法会先调用;初始化前前置处理然后调用对bean进行初始化最后调用,初始化后置处理。会遍历所有的,执行每个的方法,如果某个返回null,则直接退出循环,不再执行后面的。

Lin_Willen的博客 1054

Spring注解驱动原理及源码,深入理解Spring注解驱动

官方 Wiki 原文:基本定义:Spring 组合注解(Composed Annotations)中的元注允许是 Spring 模式注解(Stereotype Annotation)与其他 Spring 功能性注解的任意组合。官方 Wiki 原文:官方 Wiki 原文:(1)驱动注解:@EnableXXX,导入注解:@Import 具体实现/*** 激活 "HelloWorld" 模块注解。

秃了也弱了 1043

索引:《Spring注解驱动开发》学习笔记

《Spring注解驱动开发》学习笔记1.Spring注解驱动开发的概述2.使用@Configuration和@Bean给容器中注册组件3.使用@ComponentScan自动扫描组件并指定扫描规则4.自定义TypeFilter指定@ComponentScan注解的过滤规则 1.Spring注解驱动开发的概述 https://liayun.blog.youkuaiyun.com/article/details/110218278 2.使用@Configuration和@Bean给容器中注册组件 https://liayu

weixin_48033662的博客 2108
上一篇: 【设计模式】
下一篇: 【spring源码】二、bean定义、工厂
hancoder
博客等级 码龄9年 4135粉丝 167原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值