Spring注解驱动开发

Spring注解驱动开发

容器

AnnotationConfigApplicationContext

配置类

从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
@Configuation等价于

包扫描

@ComponentScan,与ComponentScan注解相对应的XML配置就是context:component-scan/, 根据指定的配置自动扫描package,将符合条件的组件加入到IOC容器中;

组件添加

1. @ComponentScan

自定义扫描机制

package com.kkagr.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;

/**
 * @Author kkagr
 * @Date 2019/11/4
 * @ComponentScan value:指定要扫描的包
 * excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
 * includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
 * FilterType.ANNOTATION:按照注解
 * FilterType.ASSIGNABLE_TYPE:按照给定的类型;
 * FilterType.ASPECTJ:使用ASPECTJ表达式
 * FilterType.REGEX:使用正则指定
 * FilterType.CUSTOM:使用自定义规则
 **/
@Configuration  //告诉Spring这是一个配置类
@ComponentScans(
        value = {
                @ComponentScan(value="com.kkagr.scan",includeFilters = {
/*						@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
						@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),*/
                        @ComponentScan.Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
                },useDefaultFilters = false)
        }
)
public class EX2ComponentScanConfig {
}

package com.kkagr.config;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

public class MyTypeFilter implements TypeFilter {

	/**
	 * metadataReader:读取到的当前正在扫描的类的信息
	 * metadataReaderFactory:可以获取到其他任何类信息的
	 */
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		// TODO Auto-generated method stub
		//获取当前类注解的信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		//获取当前正在扫描的类的类信息
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		//获取当前类资源(类的路径)
		Resource resource = metadataReader.getResource();
		
		String className = classMetadata.getClassName();
		System.out.println("--->"+className);
		if(className.contains("Impl")){
			return true;
		}
		return false;
	}

}

package com.kkagr.test;

import com.kkagr.config.EX2ComponentScanConfig;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Date 2019/11/4
 **/
public class EX2ComponentScanConfigTest {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(EX2ComponentScanConfig.class);
    @Test
    public void testComponentScanConfig(){
        printBeans(applicationContext);
    }
    private void printBeans(AnnotationConfigApplicationContext applicationContext){
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : definitionNames) {
            System.out.println(name);
        }
    }
}

@Service
public class TestService {
}
@Service
public class TestServiceImpl {
}

结果如下,TestService 和TestServiceImpl 都加了Service注解,但是过滤只保留了待Impl的bean。
在这里插入图片描述

2. @Bean

Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。

而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。每次客户端请求 prototype 作用域的 Bean 时,Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。

了解 Spring 生命周期的意义就在于,可以利用 Bean 在其存活期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在 Bean 被初始化后和被销毁前执行一些相关操作。

在 Spring 中,Bean 的生命周期是一个很复杂的执行过程,我们可以利用 Spring 提供的方法定制 Bean 的创建过程。

当一个 Bean 被加载到 Spring 容器时,它就具有了生命,而 Spring 容器在保证一个 Bean 能够使用之前,会进行很多工作。Spring 容器中 Bean 的生命周期流程如图 1 所示。
在这里插入图片描述
Bean 生命周期的整个执行过程描述如下。

1)根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

2)利用依赖注入完成 Bean 中所有属性值的配置注入。

3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。

8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

10)如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。

11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

Spring 为 Bean 提供了细致全面的生命周期过程,通过实现特定的接口或 的属性设置,都可以对 Bean 的生命周期过程产生影响。虽然可以随意配置 的属性,但是建议不要过多地使用 Bean 实现接口,因为这样会导致代码和 Spring 的聚合过于紧密。

package com.kkagr.config;

import com.kkagr.bean.Car;

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

/**
 * 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);
 *}
 *
 *
 *
 * 1)、指定初始化和销毁方法;
 * 		通过@Bean指定init-method和destroy-method;
 * 2)、通过让Bean实现InitializingBean(定义初始化逻辑),
 * 				DisposableBean(定义销毁逻辑);
 * 3)、可以使用JSR250;
 * 		@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
 * 		@PreDestroy:在容器销毁bean之前通知我们进行清理工作
 * 4)、BeanPostProcessor【interface】:bean的后置处理器;
 * 		在bean初始化前后进行一些处理工作;
 * 		postProcessBeforeInitialization:在初始化之前工作
 * 		postProcessAfterInitialization:在初始化之后工作
 *
 * Spring底层对 BeanPostProcessor 的使用;
 * 		bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
 *
 * @author kkagr
 *
 */
@ComponentScan("com.kkagr.bean")
@Configuration
public class EX5BeanLifeCycleConfig {
    @Scope("prototype")
    @Bean(initMethod="init",destroyMethod="detory")
    public Car car(){
        return new Car();
    }
}

package com.kkagr.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class Cat implements InitializingBean,DisposableBean {
	
	public Cat(){
		System.out.println("cat constructor...");
	}
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...destroy...");
	}

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

}

package com.kkagr.bean;

import org.springframework.stereotype.Component;

@Component
public class Car {
	
	public Car(){
		System.out.println("car constructor...");
	}
	
	public void init(){
		System.out.println("car ... init...");
	}
	
	public void detory(){
		System.out.println("car ... detory...");
	}

}

package com.kkagr.test;

import com.kkagr.config.EX5BeanLifeCycleConfig;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class EX5BeanLifeCycleConfigTest {
    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(EX5BeanLifeCycleConfig.class);
        System.out.println("容器创建完成...");

        applicationContext.getBean("car");
        //关闭容器
        applicationContext.close();
    }
}

运行结果
在这里插入图片描述
在EX5BeanLifeCycleConfig加上//@Scope(“prototype”)注释后
在这里插入图片描述

3. @Configuration
4. @Service

一般在service上使用

5. @Controller

一般在controller上使用

6. @Repository

一般在dao层上使用

7. @Conditional
8. @Primary
9. @Lazy

懒加载,在调用的时候在调用构造方法,一般是在容器初始化时调用

10. @Scope
11. @Import
12. ImportSelector
13. 工厂模式FactoryBean

1.注册组件

package com.kkagr.config;

import com.kkagr.bean.Color;
import com.kkagr.bean.ColorFactoryBean;
import com.kkagr.bean.Person;
import com.kkagr.bean.Red;
import com.kkagr.condition.LinuxCondition;
import com.kkagr.condition.MyImportBeanDefinitionRegistrar;
import com.kkagr.condition.MyImportSelector;
import com.kkagr.condition.WindowsCondition;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

/**
 * @Date 2019/11/4
 **/
//类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效;
@Conditional({WindowsCondition.class})
@Configuration  //告诉Spring这是一个配置类
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
//@Import导入组件,id默认是组件的全类名
public class EX3ImportBeanConfig {
//默认是单实例的
    /**
     * ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * ConfigurableBeanFactory#SCOPE_SINGLETON
     * org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST  request
     * org.springframework.web.context.WebApplicationContext#SCOPE_SESSION	 sesssion
     * @return\
     * @Scope:调整作用域
     * prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
     * 					每次获取的时候才会调用方法创建对象;
     * singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。
     * 			以后每次获取就是直接从容器(map.get())中拿,
     * request:同一次请求创建一个实例
     * session:同一个session创建一个实例
     *
     * 懒加载:
     * 		单实例bean:默认在容器启动的时候创建对象;
     * 		懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
     *
     */
	//@Scope("prototype")
    @Lazy
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加Person....");
        return new Person("张三", 25);
    }

    /**
     * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
     *
     * 如果系统是windows,给容器中注册("bill")
     * 如果是linux系统,给容器中注册("linus")
     */

    @Bean("bill")
    public Person person01(){
        return new Person("Bill Gates",62);
    }

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person02(){
        return new Person("linus", 48);
    }

    /**
     * 给容器中注册组件;
     * 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
     * 2)、@Bean[导入的第三方包里面的组件]
     * 3)、@Import[快速给容器中导入一个组件]
     * 		1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
     * 		2)、ImportSelector:返回需要导入的组件的全类名数组;
     * 		3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中
     * 4)、使用Spring提供的 FactoryBean(工厂Bean);
     * 		1)、默认获取到的是工厂bean调用getObject创建的对象
     * 		2)、要获取工厂Bean本身,我们需要给id前面加一个&
     * 			&colorFactoryBean
     */
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
}

package com.kkagr.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;

@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {

    private ApplicationContext applicationContext;

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

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

    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        // TODO Auto-generated method stub
        String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
        System.out.println("解析的字符串:"+resolveStringValue);
    }




}

package com.kkagr.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断是否linux系统
public class LinuxCondition implements Condition {

	/**
	 * ConditionContext:判断条件能使用的上下文(环境)
	 * AnnotatedTypeMetadata:注释信息
	 */
	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;
	}

}

package com.kkagr.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断是否windows系统
public class WindowsCondition implements Condition {

	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment environment = context.getEnvironment();
		String property = environment.getProperty("os.name");
		if(property.contains("Windows")){
			return true;
		}
		return false;
	}

}

package com.kkagr.condition;

import com.kkagr.bean.RainBow;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:BeanDefinition注册类;
	 * 		把所有需要添加到容器中的bean;调用
	 * 		BeanDefinitionRegistry.registerBeanDefinition手工注册进来
	 */
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		boolean definition = registry.containsBeanDefinition("com.kkagr.bean.Red");
		boolean definition2 = registry.containsBeanDefinition("com.kkagr.bean.Blue");
		if(definition && definition2){
			//指定Bean定义信息;(Bean的类型,Bean。。。)
			RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
			//注册一个Bean,指定bean名
			registry.registerBeanDefinition("rainBow", beanDefinition);
		}
	}

}

package com.kkagr.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {

	//返回值,就是到导入到容器中的组件全类名
	//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
		//importingClassMetadata
		//方法不要返回null值
		return new String[]{"com.kkagr.bean.Blue","com.kkagr.bean.Yellow"};
	}

}

package com.kkagr.test;

import com.kkagr.bean.Blue;
import com.kkagr.bean.Person;
import com.kkagr.config.EX3ImportBeanConfig;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import java.util.Map;

/**
 * @Author kkagr
 * @Date 2019/11/4
 **/
public class EX3ImportBeanConfigTest {

    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(EX3ImportBeanConfig.class);


    @Test
    public void testImport(){
        printBeans(applicationContext);
        Blue bean = applicationContext.getBean(Blue.class);
        System.out.println(bean);

        //工厂Bean获取的是调用getObject创建的对象
        Object bean2 = applicationContext.getBean("colorFactoryBean");
        Object bean3 = applicationContext.getBean("colorFactoryBean");
        System.out.println("bean的类型:"+bean2.getClass());
        System.out.println(bean2 == bean3);

        Object bean4 = applicationContext.getBean("&colorFactoryBean");
        System.out.println(bean4.getClass());
    }

    private void printBeans(AnnotationConfigApplicationContext applicationContext){
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : definitionNames) {
            System.out.println(name);
        }
    }

    @Test
    public void test03(){
        String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        //动态获取环境变量的值;Windows 10
        String property = environment.getProperty("os.name");
        System.out.println(property);
        for (String name : namesForType) {
            System.out.println(name);
        }
       Map <String, Person> persons = applicationContext.getBeansOfType(Person.class);
        System.out.println(persons);
        Object bean = applicationContext.getBean("person");
        Object bean2 = applicationContext.getBean("person");
        System.out.println(bean == bean2);

    }

}

其他的类都是创建了一个构造方法,就忽不写了
执行testimport运行结果如下
在这里插入图片描述
执行test03结果如下
在这里插入图片描述

组件赋值

1. @Value
package com.kkagr.bean;

import org.springframework.beans.factory.annotation.Value;

public class Person {

    //使用@Value赋值;
    //1、基本数值
    //2、可以写SpEL; #{}
    //3、可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值)

    //@Value("张三")
    private String name;
    //@Value("#{20-2}")
    private Integer age;

    //@Value("${person.nickName}")
    private String nickName;



    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }

    public Person(String name, Integer age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Person() {
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
    }

}

配置类中引入@PropertySource(value={“classpath:/person.properties”})

person.nickName=小李四
2. @Autowired
package com.kkagr.config;

import com.kkagr.bean.Car;
import com.kkagr.bean.Color;
import com.kkagr.dao.BookDao;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * 自动装配;
 * 		Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;
 *
 * 1)、@Autowired:自动注入:
 * 		1)、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值
 * 		2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
 * 							applicationContext.getBean("bookDao")
 * 		3)、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
 * 		4)、自动装配默认一定要将属性赋值好,没有就会报错;
 * 			可以使用@Autowired(required=false);
 * 		5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
 * 				也可以继续使用@Qualifier指定需要装配的bean的名字
 * 		BookService{
 * 			@Autowired
 * 			BookDao  bookDao;
 * 		}
 *
 * 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)、[标注在方法位置]:@Bean+方法参数;参数从容器中获取;默认不写@Autowired效果是一样的;都能自动装配
 * 		2)、[标在构造器上]:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
 * 		3)、放在参数位置:
 *
 * 4)、自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);
 * 		自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
 * 		把Spring底层一些组件注入到自定义的Bean中;
 * 		xxxAware:功能使用xxxProcessor;
 * 			ApplicationContextAware==》ApplicationContextAwareProcessor;
 *
 *
 * @author kkagr
 *
 */
@Configuration
@ComponentScan({"com.kkagr.service","com.kkagr.dao",
        "com.kkagr.controller","com.kkagr.bean"})
public class EX4AutowiredConfig {

    @Primary
    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLable("2");
        return bookDao;
    }

    /**
     * @Bean标注的方法创建对象的时候,方法参数的值从容器中获取
     * @param car
     * @return
     */
    @Bean
    public Color color(Car car){
        Color color = new Color();
        color.setCar(car);
        return color;
    }
}

package com.kkagr.service;

import com.kkagr.dao.BookDao;

import org.springframework.stereotype.Service;

import javax.inject.Inject;

/**
 * @Date 2019/11/4
 **/
@Service
public class BookService {

    //@Qualifier("bookDao")
    //@Autowired(required=false)
    //@Resource(name="bookDao2")
    @Inject
    private BookDao bookDao;

    public void print(){
        System.out.println(bookDao);
    }

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


package com.kkagr.dao;

import org.springframework.stereotype.Repository;

//名字默认是类名首字母小写
@Repository
public class BookDao {

    private String lable = "1";

    public String getLable() {
        return lable;
    }

    public void setLable(String lable) {
        this.lable = lable;
    }

    @Override
    public String toString() {
        return "BookDao [lable=" + lable + "]";
    }
}

package com.atguigu.bean;

public class Color {
	
	private Car car;

	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "Color [car=" + car + "]";
	}
	
	

}

package com.kkagr.test;

import com.kkagr.bean.Boss;
import com.kkagr.bean.Car;
import com.kkagr.bean.Color;
import com.kkagr.config.EX4AutowiredConfig;
import com.kkagr.service.BookService;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Date 2019/11/4
 **/
public class EX4AutowiredConfigTest {
    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(EX4AutowiredConfig.class);

        BookService bookService = applicationContext.getBean(BookService.class);
        System.out.println(bookService);

        //BookDao bean = applicationContext.getBean(BookDao.class);
        //System.out.println(bean);

        Boss boss = applicationContext.getBean(Boss.class);
        System.out.println(boss);
        Car car = applicationContext.getBean(Car.class);
        System.out.println(car);

        Color color = applicationContext.getBean(Color.class);
        System.out.println(color);
        System.out.println(applicationContext);
        applicationContext.close();
    }
}

在这里插入图片描述

3. @PropertySource
4. @PropertySources
5. @Profile
package com.kkagr.config;

import com.kkagr.bean.Yellow;
import com.mchange.v2.c3p0.ComboPooledDataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import javax.sql.DataSource;

/**
 * Profile:
 * 		Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
 *
 * 开发环境、测试环境、生产环境;
 * 数据源:(/A)(/B)(/C);
 *
 *
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
 *
 * 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
 * 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
 * 3)、没有标注环境标识的bean在,任何环境下都是加载的;
 */

@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class EX6ProfileConfig  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;
    }

    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        // TODO Auto-generated method stub
        this.valueResolver = resolver;
        driverClass = valueResolver.resolveStringValue("${db.driverClass}");
    }

}


package com.kkagr.test;

import com.kkagr.bean.Yellow;
import com.kkagr.config.EX6ProfileConfig;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.sql.DataSource;

/**
 * @Date 2019/11/4
 **/
public class EX6ProfileConfigTest {
    //1、使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test
    //2、代码的方式激活某种环境;
    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext();
        //1、创建一个applicationContext
        //2、设置需要激活的环境
        applicationContext.getEnvironment().setActiveProfiles("dev");
        //3、注册主配置类
        applicationContext.register(EX6ProfileConfig.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();
    }

}

在这里插入图片描述

组件注入

1. 方法参数
2. 构造器注入
3. ApplicationContextAware
4. xxxAware

AOP

1. @EnableAspectJAutoProxy
2. @Before/@After/@AfterReturning/@AfterThrowing/@Around
3. @Pointcut
package com.kkagr.config;

import com.kkagr.aop.LogAspects;
import com.kkagr.aop.MathCalculator;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.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);解析BeforeInstantiation
 * 						希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续
 * 						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)、效果:
 * 					正常执行:前置通知-》目标方法-》后置通知-》返回通知
 * 					出现异常:前置通知-》目标方法-》后置通知-》异常通知
 *
 *
 *
 */
@EnableAspectJAutoProxy
@Configuration
public class EX7AopConfig {
    //业务逻辑类加入容器中
    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    //切面类加入到容器中
    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}

package com.kkagr.aop;

public class MathCalculator {
	
	public int div(int i,int j){
		System.out.println("MathCalculator...div...");
		return i/j;	
	}

}

package com.kkagr.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import java.util.Arrays;

/**
 * 切面类
 *
 * @Aspect: 告诉Spring当前类是一个切面类
 *
 */
@Aspect
public class LogAspects {

	//抽取公共的切入点表达式
	//1、本类引用
	//2、其他的切面引用
	@Pointcut("execution(public int com.kkagr.aop.MathCalculator.*(..))")
	public void pointCut(){};

	//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
	@Before("pointCut()")
	public void logStart(JoinPoint joinPoint){
		Object[] args = joinPoint.getArgs();
		System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
	}

	@After("com.kkagr.aop.LogAspects.pointCut()")
	public void logEnd(JoinPoint joinPoint){
		System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
	}

	//JoinPoint一定要出现在参数表的第一位
	@AfterReturning(value="pointCut()",returning="result")
	public void logReturn(JoinPoint joinPoint,Object result){
		System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
	}

	@AfterThrowing(value="pointCut()",throwing="exception")
	public void logException(JoinPoint joinPoint,Exception exception){
		System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
	}

}

package com.kkagr.config;

import com.kkagr.aop.LogAspects;
import com.kkagr.aop.MathCalculator;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.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);解析BeforeInstantiation
 * 						希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续
 * 						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)、效果:
 * 					正常执行:前置通知-》目标方法-》后置通知-》返回通知
 * 					出现异常:前置通知-》目标方法-》后置通知-》异常通知
 *
 *
 *
 */
@EnableAspectJAutoProxy
@Configuration
public class EX7AopConfig {
    //业务逻辑类加入容器中
    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    //切面类加入到容器中
    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}

执行结果如下
在这里插入图片描述

声明式事务

1. @EnableTransactionManagement
2. @Transactional
package com.kkagr.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * 声明式事务:
 * 
 * 环境搭建:
 * 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.kkagr.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类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//注册事务管理器在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
	

}

在这里插入代码片

扩展原理

BeanFactoryPostProcessor

1. Spring容器标准初始化之后执行(BeanPostProcessor之前),此时bean还未创建
2. Spring容器初始化两大步

BeanDefinitionRegistryPostProcessor

1. BeanFactoryPostProcessor子类,可自定义添加bean定义
2. BeanDefinetionRegistry

ApplicationListener

1. @EventListener

Spring容器创建过程

package com.kkagr.ext;


import com.kkagr.bean.Blue;

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

/**
 * 扩展原理:
 * BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的
 *
 * 1、BeanFactoryPostProcessor:beanFactory的后置处理器;
 * 		在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容;
 * 		所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建
 *
 *
 * BeanFactoryPostProcessor原理:
 * 1)、ioc容器创建对象
 * 2)、invokeBeanFactoryPostProcessors(beanFactory);
 * 		如何找到所有的BeanFactoryPostProcessor并执行他们的方法;
 * 			1)、直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法
 * 			2)、在初始化创建其他组件前面执行
 *
 * 2、BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
 * 		postProcessBeanDefinitionRegistry();
 * 		在所有bean定义信息将要被加载,bean实例还未创建的;
 *
 * 		优先于BeanFactoryPostProcessor执行;
 * 		利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件;
 *
 * 	原理:
 * 		1)、ioc创建对象
 * 		2)、refresh()-》invokeBeanFactoryPostProcessors(beanFactory);
 * 		3)、从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件。
 * 			1、依次触发所有的postProcessBeanDefinitionRegistry()方法
 * 			2、再来触发postProcessBeanFactory()方法BeanFactoryPostProcessor;
 *
 * 		4)、再来从容器中找到BeanFactoryPostProcessor组件;然后依次触发postProcessBeanFactory()方法
 *
 * 3、ApplicationListener:监听容器中发布的事件。事件驱动模型开发;
 * 	  public interface ApplicationListener<E extends ApplicationEvent>
 * 		监听 ApplicationEvent 及其下面的子事件;
 *
 * 	 步骤:
 * 		1)、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)
 * 			@EventListener;
 * 			原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener;
 *
 * 		2)、把监听器加入到容器;
 * 		3)、只要容器中有相关事件的发布,我们就能监听到这个事件;
 * 				ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件;
 * 				ContextClosedEvent:关闭容器会发布这个事件;
 * 		4)、发布一个事件:
 * 				applicationContext.publishEvent();
 *
 *  原理:
 *  	ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的时间]、ContextClosedEvent;
 *  1)、ContextRefreshedEvent事件:
 *  	1)、容器创建对象:refresh();
 *  	2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
 *  2)、自己发布事件;
 *  3)、容器关闭会发布ContextClosedEvent;
 *
 *  【事件发布流程】:
 *  	3)、publishEvent(new ContextRefreshedEvent(this));
 *  			1)、获取事件的多播器(派发器):getApplicationEventMulticaster()
 *  			2)、multicastEvent派发事件:
 *  			3)、获取到所有的ApplicationListener;
 *  				for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
 *  				1)、如果有Executor,可以支持使用Executor进行异步派发;
 *  					Executor executor = getTaskExecutor();
 *  				2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event);
 *  				 拿到listener回调onApplicationEvent方法;
 *
 *  【事件多播器(派发器)】
 *  	1)、容器创建对象:refresh();
 *  	2)、initApplicationEventMulticaster();初始化ApplicationEventMulticaster;
 *  		1)、先去容器中找有没有id=“applicationEventMulticaster”的组件;
 *  		2)、如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
 *  			并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster;
 *
 *  【容器中有哪些监听器】
 *  	1)、容器创建对象:refresh();
 *  	2)、registerListeners();
 *  		从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;
 *  		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
 *  		//将listener注册到ApplicationEventMulticaster中
 *  		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
 *
 *   SmartInitializingSingleton 原理:->afterSingletonsInstantiated();
 *   		1)、ioc容器创建对象并refresh();
 *   		2)、finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean;
 *   			1)、先创建所有的单实例bean;getBean();
 *   			2)、获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的;
 *   				如果是就调用afterSingletonsInstantiated();
 * 		
 * 
 *
 */
@ComponentScan("com.kkagr.ext")
@Configuration
public class ExtConfig {
	
	@Bean
	public Blue blue(){
		return new Blue();
	}

}

package com.kkagr.ext;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {

	//当容器中发布此事件以后,方法触发
	public void onApplicationEvent(ApplicationEvent event) {
		// TODO Auto-generated method stub
		System.out.println("收到事件:"+event);
	}

}

package com.kkagr.ext;

import com.kkagr.bean.Blue;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor{

	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量:"+beanFactory.getBeanDefinitionCount());
	}

	//BeanDefinitionRegistry Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例;
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("postProcessBeanDefinitionRegistry...bean的数量:"+registry.getBeanDefinitionCount());
		//RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
		AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition();
		registry.registerBeanDefinition("hello", beanDefinition);
	}

}

package com.kkagr.ext;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory...");
		int count = beanFactory.getBeanDefinitionCount();
		String[] names = beanFactory.getBeanDefinitionNames();
		System.out.println("MyBeanFactoryPostProcessor"+count+" 个Bean");
		System.out.println(Arrays.asList(names));
	}

}

package com.atguigu.ext;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class UserService {

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

}

package com.kkagr.test;

import com.kkagr.ext.ExtConfig;

import org.junit.Test;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Ext {

	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext  = new AnnotationConfigApplicationContext(ExtConfig.class);


		//发布事件;
		applicationContext.publishEvent(new ApplicationEvent(new String("我发布的时间")) {
		});
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
		applicationContext.close();
	}

}

在这里插入图片描述

web

servlet3.0

1. ServletContainerInitializer
2. Registration
3. ServletContext

异步请求

1. servlet3.0异步处理
2. 返回Callable
3. 返回DeferredResult

在这里插入图片描述

package com.kkagr.config;


import com.kkagr.controller.MyFirstInterceptor;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

//SpringMVC只扫描Controller;子容器
//useDefaultFilters=false 禁用默认的过滤规则;
@ComponentScan(value="com.kkagr",includeFilters={
		@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters=false)
@EnableWebMvc
public class AppConfig  extends WebMvcConfigurerAdapter  {

	//定制

	//视图解析器
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		// TODO Auto-generated method stub
		//默认所有的页面都从 /WEB-INF/ xxx .jsp
		//registry.jsp();
		registry.jsp("/WEB-INF/views/", ".jsp");
	}

	//静态资源访问
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		// TODO Auto-generated method stub
		configurer.enable();
	}

	//拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// TODO Auto-generated method stub
		//super.addInterceptors(registry);
		registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**");
	}

}

package com.kkagr.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

//Spring的容器不扫描controller;父容器
@ComponentScan(value="com.kkagr",excludeFilters={
		@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
public class RootConfig {

}

package com.kkagr.controller;

import java.util.UUID;
import java.util.concurrent.Callable;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import com.kkagr.service.DeferredResultQueue;


@Controller
public class AsyncController {


	@ResponseBody
	@RequestMapping("/createOrder")
	public DeferredResult<Object> createOrder(){
		DeferredResult<Object> deferredResult = new DeferredResult<>((long)3000, "create fail...");

		DeferredResultQueue.save(deferredResult);

		return deferredResult;
	}


	@ResponseBody
	@RequestMapping("/create")
	public String create(){
		//创建订单
		String order = UUID.randomUUID().toString();
		DeferredResult<Object> deferredResult = DeferredResultQueue.get();
		deferredResult.setResult(order);
		return "success===>"+order;
	}

	/**
	 * 1、控制器返回Callable
	 * 2、Spring异步处理,将Callable 提交到 TaskExecutor 使用一个隔离的线程进行执行
	 * 3、DispatcherServlet和所有的Filter退出web容器的线程,但是response 保持打开状态;
	 * 4、Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理;
	 * 5、根据Callable返回的结果。SpringMVC继续进行视图渲染流程等(从收请求-视图渲染)。
	 *
	 * preHandle.../springmvc-annotation/async01
	 主线程开始...Thread[http-bio-8081-exec-3,5,main]==>1513932494700
	 主线程结束...Thread[http-bio-8081-exec-3,5,main]==>1513932494700
	 =========DispatcherServlet及所有的Filter退出线程============================

	 ================等待Callable执行==========
	 副线程开始...Thread[MvcAsync1,5,main]==>1513932494707
	 副线程开始...Thread[MvcAsync1,5,main]==>1513932496708
	 ================Callable执行完成==========

	 ================再次收到之前重发过来的请求========
	 preHandle.../springmvc-annotation/async01
	 postHandle...(Callable的之前的返回值就是目标方法的返回值)
	 afterCompletion...

	 异步的拦截器:
	 1)、原生API的AsyncListener
	 2)、SpringMVC:实现AsyncHandlerInterceptor;
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/async01")
	public Callable<String> async01(){
		System.out.println("主线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());

		Callable<String> callable = new Callable<String>() {
			public String call() throws Exception {
				System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
				Thread.sleep(2000);
				System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
				return "Callable<String> async01()";
			}
		};

		System.out.println("主线程结束..."+Thread.currentThread()+"==>"+System.currentTimeMillis());
		return callable;
	}

}

package com.kkagr.controller;


import com.kkagr.service.HelloService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
	
	@Autowired
	HelloService helloService;
	
	
	@ResponseBody
	@RequestMapping("/hello")
	public String hello(){
		String hello = helloService.sayHello("tomcat..");
		return hello;
	}
	
	//  /WEB-INF/views/success.jsp
	@RequestMapping("/suc")
	public String success(){
		return "success";
	}
	

}

package com.kkagr.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyFirstInterceptor implements HandlerInterceptor {

	//目标方法运行之前执行
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// TODO Auto-generated method stub
		System.out.println("preHandle..."+request.getRequestURI());
		return true;
	}

	//目标方法执行正确以后执行
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
						   ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("postHandle...");

	}

	//页面响应以后执行
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		System.out.println("afterCompletion...");
	}

}

package com.kkagr.service;

import org.springframework.web.context.request.async.DeferredResult;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

public class DeferredResultQueue {
	
	private static Queue<DeferredResult<Object>> queue = new ConcurrentLinkedQueue<DeferredResult<Object>>();
	
	public static void save(DeferredResult<Object> deferredResult){
		queue.add(deferredResult);
	}
	
	public static DeferredResult<Object> get( ){
		return queue.poll();
	}

}

package com.kkagr.service;

import org.springframework.stereotype.Service;

@Service
public class HelloService {
	
	public String sayHello(String name){
		
		return "Hello "+name;
	}

}

package com.kkagr;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.kkagr.config.AppConfig;
import com.kkagr.config.RootConfig;

//web容器启动的时候创建对象;调用方法来初始化容器以前前端控制器
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	//获取根容器的配置类;(Spring的配置文件)   父容器;
	@Override
	protected Class<?>[] getRootConfigClasses() {
		// TODO Auto-generated method stub
		return new Class<?>[]{RootConfig.class};
	}

	//获取web容器的配置类(SpringMVC配置文件)  子容器;
	@Override
	protected Class<?>[] getServletConfigClasses() {
		// TODO Auto-generated method stub
		return new Class<?>[]{AppConfig.class};
	}

	//获取DispatcherServlet的映射信息
	//  /:拦截所有请求(包括静态资源(xx.js,xx.png)),但是不包括*.jsp;
	//  /*:拦截所有请求;连*.jsp页面都拦截;jsp页面是tomcat的jsp引擎解析的;
	@Override
	protected String[] getServletMappings() {
		// TODO Auto-generated method stub
		return new String[]{"/"};
	}

}

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值