基于Annotation的spring

1,@Configuration注解,表明这是一个配置类

	相当于一个application.xml配置文件

2,@Bean 向容器中注册一个bean,类型为返回值类型,id默认是用方法名作为id,也可以指定id-》@Bean(“person”) 表示id为person

	相当于xml中的<bean id="xxx"  class="com.atsun.xxx">

在IOC容器启动时,会将方法的返回对象放入到容器中 默认方法名作为组件id

XML配置

    <bean id="person" class="com.atsun.bean.Person">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="20"></property>
    </bean>
JAVA配置类
@Configuration
@Import({Color.class,MyImportSelect.class,MyImportBeanDefinitionRegistrar.class}) //快速引入组件	
public void MyConfig{
	
	@Bean("person")
	public Person getPerson(){
		
		return new Person("zhangsan",20);
	}
}

public Person{
	........
}

public @interface Bean {
    @AliasFor("name")
    String[] value() default {};

    @AliasFor("value")
    String[] name() default {};








@Configuration	声明这是一个配置类
@Bean		给容器中注册一个bean,类型为返回值类型。id默认为方法名,bean注解中可传入参数指定id
@Import		快速给容器中导入一个组件	
			1)@Import({Color.class}) 容器中就会自动注册这个组件,id默认时全类名
			2@Import({MyImportSelect.class}:ImportSelector:返回需要导入的组件的全类名数组	引入多个Bean
					实现ImportSelect接口重写selectImports方法返回要导入的组件的全类名数组	
			3)@Import({ImportBeanDefinitionRegistrar})
					自定义类实现ImportBeanDefinitionRegistrar接口,手动注册bean到容器中
使用Spring提供的FactoryBean(工厂Bean接口)
	实现工厂bean接口(FactoryBean)
	默认获取到的bean是工厂bean调用getObject()方法创建的对象,
	要获取工厂bean本身,我们需要给id前面加上&   xxxxx.getBean("&colorFactoryBean")
					
			



2------@Import({MyImportSelect.class}//返回值就是要导入到容器中的组件的全类名
    //AnnotationMetadata    当前标注@Import注解的类的所有注解信息
public class MyImportSelect implements ImportSelector {
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.atsun.Person1","com.atsun.Person2"};
    }
}


3----3)@Import({MyImportBeanDefinitionRegistrar.class})
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean flag = registry.containsBeanDefinition("com.atsun.bean.Color");//在容器中是否有这个bean
        if(flag){
        注册bean-->
            //指定bean的定义信息(可以指定Bean的类型,作用域等)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Red.class);
            //注册一个bean,指定bean名称
            registry.registerBeanDefinition("red",beanDefinition);
        }
    }
}

 //虽然装配的是ColorFactoryBean,但实际返回的是工厂bean调用getObject()方法创建的对象
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
//创建spring定义的工厂bean
public class ColorFactoryBean implements FactoryBean<Color> {

    //返回一个color对象,这个对象会添加到容器中
    public Color getObject() throws Exception {
        return new Color();
    }

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

    //是单例吗 true 是单实例,在容器中保存一份
    //          false   多实例 每次获取都会创建一个新的bean(就是调用getObject()方法)
    public boolean isSingleton() {
        return true;
    }
}

2,注解扫描

	XML	配置

<!--    包扫描 只要标注了@Controller  @Service @Component   @Repository  都会被自动扫描加入容器-->
    <context:component-scan base-package="com.atsun" use-default-filters="false">
        <context:exclude-filter type="annotation" expression=""/>
        <context:include-filter type="annotation" expression=""/> 只包含,需要禁用默认规则
    </context:component-scan>

    <bean id="person" class="com.atsun.bean.Person">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="20"></property>
    </bean>

JAVA配置类


@Configuration
@ComponentScan(value = "com.atsun",includeFilters = {
       /* @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),*/
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})	自定义扫描,实现TypeFilter 接口
},useDefaultFilters = false)
public class MainConfig {

    @Bean(name = "person")
    public Person getPerson(){
        return new Person("张三",18);
    }
}



/*
        @ComponentScan  value:指定要扫描的包
            --excludeFilters =Filter[] 排除那些组件,例如:排除包含Controller和service注解的
            --includeFilters =Filter[] 包含那些组件    需要禁用默认规则useDefaultFilters = false
               --FilterType.ANNOTATION          按照注解
               --FilterType.ASSIGNABLE_TYPE     按照给定的类型
               --ASPECTJ,                       按照切入点表达式
               --REGEX,                         按照正则匹配
               --CUSTOM;                        自定义过滤规则
*/


----》自定义过滤规则	CUSTOM
//MetadataReader 读取到当前正在扫描的类信息
//MetadataReaderFactory 可以获取到其他任何类信息
public class MyTypeFilter implements TypeFilter {
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类的资源信息(类的路径)
        Resource resource = metadataReader.getResource();

        //获取当前类名
        String className = classMetadata.getClassName();

        System.out.println(className);

        if(className.contains("er")){
            return true;
        }
        return false;
    }
}

作用域 @Scope注解

@Configuration
public class MyConfug2 {

   

    @Scope(value = "singleton")
    @Lazy	对单实例启用
    @Bean(value = "person")
    public Person getPerson(){

        return new Person("zhangsan",22);
    }
}

 //默认时单实例的 
 	   @Scope     
		     prototype 多实例的 			
		    		IOC容器启动并不会去调用方法创建对象放入容器中
		    		每次获取的时候才会调用方法创建对象,每次获取都会创建一个对象
		    	
		     singleton单实例 默认值  	
		     		IOC容器启动会调用方法创建对象放入到ioc容器中  
		  			以后每次获取直接从容器中拿       
		    
		     request 同一次请求创建一个    
		     session 同一个session创建一个

     @Lazy   懒加载,对单实例有效
     *  单实例bean 默认在容器启动时创建对象
     *  懒加载     容器启动不创建对象,第一次使用(获取)Bean创建对象,并初始化

按照条件判断给容器中注册组件

@Conditional({参数必须为Condition类型}) Condition是一个接口 所以需要继承Contidion,并实现matches方法,返回true则满足
public @interface Conditional {
Class<? extends Condition>[] value();
}
既可以作用在方法上又可以作用在类上


@Configuration
//类中组件统一设置,满足当前条件,这个类中的配置的说有bean才能生效
@Conditional({LishiCon.class})	如果LishiCon-->matches返回true则当前类中注入的bean有效
public class MyConfug2 {


    @Scope(value = "singleton")
    @Lazy       //懒加载 只对单实例有效
    @Bean(value = "person")
    public Person getPerson() {

        return new Person("zhangsan", 22);
    }
	
	 @Bean("zhangsan")
    @Conditional({LishiCon.class})
    public Person person1(){

        return new Person("zhangsan",21);
    }

    @Bean("lishi")
    @Conditional(zhangsanCon.class)
    public Person person2(){

        return new Person("lishi",23);
    }
}

Condition.class

public class LishiCon implements Condition {


    /*
    *       conditionContext    判断条件能使用的上下文(环境)
    *       annotatedTypeMetadata   注释信息
    *
    *       如果容器中有person    则返回true,创建id为 zhangsan的容器
    * */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
		 获取bean工厂
		 ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
		 获取环境变量
		  Environment environment = conditionContext.getEnvironment();
		   
		 //获取bean定义的注册类,所有的bean都在这里注册    能注册 移除 查询 bean
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
		//在ioc容器中有person时生效
        boolean person1 = registry.containsBeanDefinition("person");
        System.out.println(person1+"-->");
        return person1;
    }
}


Bean的生命周期

bean创建-----------------》初始化-----------------------销毁过程
容器管理bean的生命周期
我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法

	指定初始化和销毁方法
	xml		init-method="该类初始化方法名"		destroy-method="该类销毁方法名"

1、启动Spring容器
2、创建Bean对象 ----> 实际是在调用Bean对象的构造器
3、给Bean添加属性
4、调用Bean对象的初始化init-method
5、getBean获取某个bean对象,调用bean对象的某一个方法
6、调用Bean对象的销毁方法destory-method
7、Spring容器销毁

XML

<bean id="" class="" init-method="该类初始化方法名" destroy-method="该类销毁方法名"/>

注解

BeanPostProcessor.postProcessBeforeInitialization				初始化之前
	初始化		对象完成并赋值好,调用初始化方法。	多实例bean获取bean才创建容器,再进行初始化
BeanPostProcessor.postProcessAfterInitialization				初始化之后
	销毁		容器关闭的时候										多实例bean容器不会管理这个bean,容器不会调用销毁方法

1)指定初始化和销毁方法
		通过@Bean指定init-method和	destory-method
   public void test01(){
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfigofLifeCycle.class);
        System.out.println("IOC  created finish.......");

        //关闭容器
        applicationContext.close();
    }
    
@Configuration
public class MainConfigofLifeCycle {
    @Bean(initMethod = "init",destroyMethod = "destory")
    public Car car(){
        return new Car();
    }
}

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

控制台
	car constructor....					容器创建
	car.....init....					初始化
	IOC  created finish.......			创建完成
	car .....destory...					销毁

2)通过让bean实现InitalizingBean(定义初始化逻辑)
								DisposableBean(定义销毁逻辑)

@Component
public class Cat implements InitializingBean, DisposableBean {
    public Cat() {
        System.out.println("cat   constructor.....");
    }
    //销毁,单实例bean容器关闭后调用
    public void destroy() throws Exception {

        System.out.println("destory........");
    }
    //初始化   bena创建完成并且属性都赋好值以后调用
    public void afterPropertiesSet() throws Exception {

        System.out.println("afterPropertiesSet.....");
    }
}


@Configuration
@ComponentScan("com.atsun.bean")
public class MainConfigofLifeCycle {

   /* @Bean(initMethod = "init",destroyMethod = "destory")
    public Car car(){
        return new Car();
    }*/

}

    public void test01(){
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfigofLifeCycle.class);
        System.out.println("IOC  created finish.......");

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

控制台
	cat   constructor.....
	afterPropertiesSet.....
	IOC  created finish.......
	destory........
3)使用JSR250
	@PostConstruct 在bean创建完成并且属性赋值完成来执行初始化
	@PreDistory		在容器销毁之前进行调用

@Component
public class Dog {
    public Dog() {
        System.out.println("Dog  constructor......");
    }

    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){

        System.out.println("@PostConstruct.......");
    }

    //在容器移除对象之前回调
    @PreDestroy
    public void distory(){
        System.out.println("@PreDestroy.........");
    }
    
}

4)BeanPostProcessor【interface】	bean的后置处理器
		在bean的初始化前后进行一些处理工作
		--postProcessBeforeInitialization	bean 任何初始化方法之前	进行后置处理工作
		--postProcessAfterInitialization		bean 任何初始化之后进行	后置处理工作
/*
* 初始化前后进行处理
* @param    bean    	刚创建的bean实例
* 			beanName    这个bean实例在容器中的名字
*
* return 可以直接返回刚创建的bean,也可以包装bean之后再返回
* */

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization.."+beanName+"..."+bean);
        return bean;
    }
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization.."+beanName+"..."+bean);
        return bean;
    }
}



控制台
	cat   constructor.....														创建bean对象
	postProcessBeforeInitialization..cat...com.atsun.bean.Cat@25359ed8			初始化方法之前
	afterPropertiesSet.....														初始化
	postProcessAfterInitialization..cat...com.atsun.bean.Cat@25359ed8			初始化方法之后
	Dog  constructor......														
	postProcessBeforeInitialization..dog...com.atsun.bean.Dog@12405818
	@PostConstruct.......
	postProcessAfterInitialization..dog...com.atsun.bean.Dog@12405818
	IOC  created finish.......
	@PreDestroy.........
	destory........

BeanPostProcessor原理

// Initialize the bean instance.初始化bean实例
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);											为bean进行属性赋值(get/set等)
			==========================================================================================================
			exposedObject = initializeBean(beanName, exposedObject, mbd);							调用初始化方法
		}

//初始化给定的bean实例,应用工厂回调
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			遍历容器中的所有BeanPostProcessors挨个执行postProcessBeforeInitialization
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);		初始化之前,应用所有的。。。
		}
		try {
			invokeInitMethods(beanName, wrappedBean, mbd);											执行初始化
		}
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);		初始化之后
		}

		return wrappedBean;
	}



遍历容器中的所有BeanPostProcessors挨个执行postProcessBeforeInitialization,返回null不会执行后面的
BeanPostProcessor.postProcessBeforeInitialization
	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

@Value注解
参数 1,基本数值
2,SPEL #{}
3,${} 取出配置文件的值(在运行时配置文件的参数都会放入换环境变量中)

  public void Test02(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
   
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);

        //获取环境变量,配置文件中的属性都会加载到环境变量中,可以根据key直接取出来
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        String property = environment.getProperty("person.nickName");
        System.out.println(property);
    }
properties
	person.nickName=xiaozhangsan
  
//PropertySource读取外部配置文件中的K/V保存到环境变量中;加载完为外部配置文件后用${}取出配置文件中的值
@Configuration
@PropertySource(value = {"classpath:/person.properties"})
public class MainConfigOfPropertyValues {
    @Bean
    public Person person(){
        return new Person();
    }
}

public class Person {
    //使用@Value赋值
    //1,基本数值
    //2,SPEL #{}
    //3,${} 取出配置文件的值(在运行环境变量的值--运行时都会放入换环境变量中)
    @Value("zhangsan")
    private String name;
    @Value("#{20-2}")
    private int age;

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



自动装配

Spring利用依赖注入(DI)完成对ioc容器中各个组件的依赖关系赋值
@Autowired:自动注入
------》required=false是否必须

     1--》	默认优先按照类型去容器中找对应的组件,找到就赋值
     2--》	如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
     3--》	没有找到就会报错	可以使用@Autowired(required=false)不是必须的,如果找到就装配找不到就不装配

@Qualifier(“组件id”)

	指定需要装配的组件id,而不是使用属性名

@Primary:让spring进行自动装配的时候,默认使用首选的bean

优先级 @Primary----》@Qualifier-----》@Autowired(默认)

@Configuration
@ComponentScan({"com.atsun.Service","com.atsun.Dao","com.atsun.controller"})
public class MainConfigOfAutowired {
    @Primary    //作为首选的
    @Bean
    public BookDao bookDao(){

        return new BookDao();
    }
}

Spring还支持使用@Resource(JSR250)和@Inject(JSR330) 【java规范】
@Resource:默认按照组件名称进行装配
@Inject:需要导入javax-inject依赖,和Autowiredz功能一样,没有required=false

@Autowired:能标注在构造器,参数,方法,属性;都是从容器中获取参数组件的值
1)标注再方法上,Spring容器创建当前对象,就会调用方法完成赋值,方法使用的参数,自定义类型的值从ioc容器中获取
2)标注在有参构造器上,自动注入构造器所需参数,如果组件只有一个有参构造器,这个有参构造器的antowired可以省略,参数位置的组件还是自动从容器中获取
3)标注在方法参数上

@Bean标注的方法创建对象的时候,方法参数值冲容器中获取(Car)

@Bean
public Color color(Car car/*自动注入,省略@Autowired*/){
	Color color=new Color();
	color.setCar(car);
	return color;
}

AOP

以前使用AOP注解需要在xml中开启基于注解的aop模式

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

现在使用配置类配置类

@EnableAsprctJAutoProxy		开启基于注解的aop模式
@Configuration
public class MainConfigOfAop{
	@Bean........
}
©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页