spring4 知识点

 

1 bean的 创建

 


  1,直接在配置文件里面写一个带有@Bean注解的方法(返回值就是那个bean对象),(name等于 方法名)

    @Bean还可以写在枚举上面


  2,使用 FactoryBean 接口(三个方法分别是创建,类型,单例),需要把它加入到spring 容器管理,@Component 或者  @Bean

    这时候 默认名字指向的是 FactoryBean  返回的元素对象实例。而不是  FactoryBean 对象的实例,使用 &默认名字 指向的FactoryBean 对象实例

    单例模式的时候元素对象放在单例池中,当多例的时候每次通过FactoryBean 实例区获取一个新的单例对象。

    

/**
 * FactoryBean 向Spring容器注册对象
 *
 * @Author ZHANGYUKUN
 */
@Component("goods")
public class GoodsFactoryBean implements FactoryBean<Goods> {
    int i = 0;

    /**
     * 返回一个元素实例
     * @return
     * @throws Exception
     */
    @Override
    public Goods getObject() throws Exception {
        Goods goods = Goods.randomGoods();
        goods.setName("goodsName" + i++);
        return goods;
    }

    /**
     * 返回类工厂元素类型
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Goods.class;
    }

    /**
     * 选择多例模式
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

  

    


  3,在 配置类里面可以 用一个 @Bean 方法的形参里面写入Spring 容器里面的 Bean 对象,这样会自动注入

    

	@Bean
	public String testParam(  GoodsService getGood1) {
		System.out.println("形式参数:" + getGood1 );

		return "testParamRT";
	}

  

  备注:只有一个默认只有满足有且只有一个同类型的对象才能注入,否者随机注入一个,需要精确注入可以使用@Qualifier("name")  

 

 

 

 

 


2 指定bean 的 初始销毁几种方法


  1 bean 类继承 ,InitializingBean,DisposableBean 接口实现对应方法


  2, 在配置注解上面指定 @Bean(destroyMethod="destroy",initMethod="afterPropertiesSet")


  3,(jsr 250 的 注解) 在方法前写上 @PreDestroy(销毁前) 和 @PostConstruct(创建以后)

 

  调用顺序  java >接口的>@Bean 指定的

	@Bean(initMethod = "initMethod",destroyMethod = "destroyMethod")
	public BeanLifecycle beanLifecycle( @Qualifier("getGood2") Goods getGood1) {
		return new BeanLifecycle();
	}

  

public class BeanLifecycle implements InitializingBean, DisposableBean {

    @PostConstruct
    public void postConstruct() throws Exception {
        System.out.println("1 postConstruct 方法 ");
    }

    @PreDestroy
    public void preDestroy() throws Exception {
        System.out.println("4 preDestroy 方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("2 InitializingBean 接口的 afterPropertiesSet 方法 ");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("5 DisposableBean 接口的 destroy  方法");
    }

    public void initMethod() throws Exception {
        System.out.println("3 initMethod 方法");
    }

    public void destroyMethod() throws Exception {
        System.out.println("6 destroyMethod 方法 ");
    }

}

  

 


3 spring bean属性的注入  

 

    @Primary  ,@Autowired ,@Qualifier,@Resource 关系

  1 同类的bean有多个实例 ,按照 类型获取的时候会获取代 @Primary 注解标注的那个

  

  2 如果没有指定那么 @Primary那么@Autowired 默认会报错,但是可以通过 @Qualifier("name") 类指定注入实例的名字

  

    @Autowired
    @Qualifier("getGood1")
    Goods goods;

  

      3 @Resource 默认就是按照字段名字找优先(没写名字的时候默认名字是字段名字),如果找不到再按照类型,并且也可以指定 字段以外的名字 @Resource(name="getGood1"),但是@Resource 不能写在方法参数上, @Qualifier可以

 

   @Resource,@Qualifier 都可以打破 @Primary的优先注入

 

 

 

 

 

4  spring的多例

 

  @Scope("prototype") 修饰的@Bean 或者 @Component 表示这个类是多例对象(spring 管理的对象默认是单例的),或者实现FactoryBean接口

 

//--------------------------------@Scope的 多例---------------------------------------------------------

	int i = 0;
	@Bean
	@Scope("prototype")
	public Goods getScopeGoods() throws Exception {
		Goods goods = Goods.randomGoods();
		goods.setName("getScopeGoods" + i++);
		return goods;
	}

 

 

    获取多例有2种办法

    1 直接通过名字在容器中获取

    

    /**
     * 通过 @Scope 获取多例对象
     */
    @Test
    public void t4(){
        logger.info("通过对象名字获取多例1:{}", SpringContextHoder.getContext().getBean("getScopeGoods") );
        logger.info("通过对象名字获取多例2:{}", SpringContextHoder.getContext().getBean("getScopeGoods") );
        logger.info("通过对象名字获取多例3:{}", SpringContextHoder.getContext().getBean("getScopeGoods") );
    }

  

    2 通过 ObjectFactory 获取(注解方式需要用这种)

  

    @Autowired
    ObjectFactory<Goods> getScopeGoods;

    /**
     * 通过ObjectFactory获取多例对象
     */
    @Test
    public void t6(){
        System.out.println( getScopeGoods.getObject() );;
    }

  

  备注: ObjectFactory <T>  方式获取多例对象,最好指定名字,在单例多例并且,并且不只一个的时候可能会找不到不你想要的那个多例对象(@Primary 在不指定名字的时候优先级最高,如果没有指定@Primary的对象,那么ObjectFactory 是有效获取多例对象的),实现factoryBean 多例和@Scope 的多例都可以这样获

  比如这样:

    @Autowired
    @Qualifier("goodsFactoryBean")
    ObjectFactory<Goods> getScopeGoods;

  

 

 

 

 

5 AnnotationConfigApplicationContext(Config.class,UserFactoryBean.class) 的 方法里面 不仅仅 可以@Configuration标注的配置类 还可以写 带有注解的组件(@Component ,@Service @Controller @Repository,等等)

 

 

 


5 @Qualifier 对 @Autowired,@Inject(需要引入inject 包) 按照类型匹配进行修饰(按照名字选择)


  @ComponentScan 指定扫描的包

 

  备注:@Inject 注解已经现在默认不能用了, 它属于 JSR 330  标准

 

 

 

6 拿到 spring 容器   

 

  1 实现 ApplicationContextAware

    这个方法其实就是在 BeanPostProcessor 里面判断是否实现了 ApplicationContextAware 接口 ,若果实现了,那么就掉指定方法设置 spring容器


  2 构造方法的参数里面写 public SpringContext(ApplicationContext applicationContext,@Qualifier("user2") User user)
    备注,这种方法只能有一个构造函数,多个不知道选那个,会默认选择无参数的那个 (如果没有无参数的那个会报错) spring 4.3 提供(spring4.3 默认会给会为 构造方法注入)


  3 直接在任意spring 管理的类中注入 spring 容器 @Inject AnnotationConfigApplicationContext context;



  4 不能通过getBean 的到

 

  @Bean参数形参注入(貌似会循环注入)

	//--------------------------------@Bean 形参获取 ApplicationContext---------------------------------------------------------
	@Bean
	public ApplicationContext getApplicationContext( ApplicationContext applicationContext)  {
		System.out.println( "通过形参获取applicationContext:" + applicationContext );
		return applicationContext;
	}

  

 构造方法参数

@Component
public class MySpringApplicationContext {

private ApplicationContext context;

//webApplicationContext是默认容器的名字
public MySpringApplicationContext(@Qualifier("webApplicationContext") ApplicationContext context) {
this.context = context;
}

public ApplicationContext getContext() {
return context;
}
}

  

测试方法

    @Autowired
    MySpringApplicationContext mySpringApplicationContext;

    @Autowired
    @Qualifier("getApplicationContext")
    ApplicationContext applicationContext;

    /**
     * 通过构造方法获取 ApplicationContent
     */
    @Test
    public void t8(){
        //通过ApplicationContextAware获取
        System.out.println( SpringContextHoder.getContext() );

        //通过构造方法获取(@bean的 方法估计也行)
        System.out.println( mySpringApplicationContext.getContext() );

        //直接注入获取
        System.out.println( applicationContext );

        //这种方式不能获取
        System.out.println( mySpringApplicationContext.getContext().getBeansOfType( ApplicationContext.class ) );
    }

  


7 几个重要的 Factory的接口

  BeanFactory,FactoryBean,ObjectFactory

 

  1 BeanFactory spring的工厂类,它不是一种类的工厂(不是只返回一种类型),而是一个容器接口,通过这个容器接口我们可以拿到spring托管的对象。

 

 

  2 FactoryBean  我们的工厂类,通过这个接口让spring给我们托管这个工厂类,从而产生 工厂里面的 对象(单例一般不需要,使用多例的时候可以借用这个 接口 来产生多例的实例对象)

 

  3 ObjectFactory

    多用于多例对象的获取, 用法: 

    @Autowired

    ObjectFactory<单例对象类型> 单例对象工厂;

  

 


  

8 几个重要的 postProcessor 接口 

    BeanPostProcessor ,BeanFactoryPostProcessor ,BeanDefinitionRegistryPostProcessor 

    执行顺序  BeanDefinitionRegistryPostProcessor >BeanFactoryPostProcessor  >BeanPostProcessor 

 

  

 1  BeanPostProcessor

     实现 BeanPostProcessor 的类可以对任何 spring管理的类的 初始化开始和完成进行监听,并且任意的修改 这个对象。

 

     备注:我们可以通过 postProcessor 对server 类调用 做参数日志(返回一个代理对象,然后在方法调用前打印参数)

     备注2: BeanPostProcessor 对所有spring管理的 类都生效。及其强大,能做的拓展及其的多

    

   

一个修改 goods 属性的 BeanPostProcessor 实现

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    //可以在spring托管的Bean 对象构造完成的前后 做一些处理,比如修改一些属性,甚至环一个实例
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(  beanName.equals("getGood1") ){
            Goods  goods1 = ((Goods)bean);
            goods1.setName(goods1.getName() + "postProcessBeforeInitialization附加");
            System.out.println(  "postProcessBeforeInitialization:" + beanName +"::"+ bean  );
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(  beanName.equals("getGood1") ){
            Goods  goods1 = ((Goods)bean);
            goods1.setName(goods1.getName() + "postProcessAfterInitialization附加2");
            System.out.println(  "postProcessAfterInitialization:" + beanName +"::"+ bean  );
        }
        return bean;
    }
}

  

  测试代码,打印修改以后的名字,打印已有的BeanPostProcessor 实现类有几个(加我写的那个一共16个)

    /**
     * 测试 BeanPostProcessor 修改对象属性
     */
    @Test
    public void t9(){
        logger.info("BeanPostProcessor 修改goods的 名字:{}", goods.getName() );
        logger.info("BeanPostProcessor 修改goods的 名字:{}", applicationContext.getBeansOfType(BeanPostProcessor.class).size() );
    }

  

 

  2 BeanFactoryPostProcessor 

    BeanFactoryPostProcessor 接口 可以拿到 所有bean 的 factroy 在 BeanPostProcessor 之前触发,这里获取到的是 spring容器对象,这时候其实没有初始化完成,如果这里获取bean,会导致bean 的提前初始化,在后面 BeanPostProcessor  执行的时候就不会在初始化这个类了(认为已经初始化完成)。

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, BeanPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor:" + beanFactory );
        //这时候很多容器初始化没完成bean 如果用了,后面 BeanPostProcessor 的流程对应的 bean 会被跳过(估计认为已经初始化完成了),注释掉下面一行以后就会执行
        System.out.println("MyBeanFactoryPostProcessor 获取对象:" + beanFactory.getBean("myGoods") );
    }



    //可以在spring托管的Bean 对象构造完成的前后 做一些处理,比如修改一些属性,甚至环一个实例
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(  beanName.equals("myGoods") ){
            Goods goods1 = ((Goods)bean);
            goods1.setName(goods1.getName() + "postProcessBeforeInitialization附加");
            System.out.println(  "MyBeanPostProcessor前:" + "修改参数" );
        }
        System.out.println(  "MyBeanPostProcessor前:" + "修改参数:"+ "beanName" );
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(  beanName.equals("myGoods") ){
            Goods  goods1 = ((Goods)bean);
            goods1.setName(goods1.getName() + "postProcessAfterInitialization附加2");
            System.out.println(  "MyBeanPostProcessor后:" + "修改参数");
        }
        return bean;
    }

  


  3 BeanDefinitionRegistryPostProcessor

    可以动态的注册spring 的 bean 对象,甚至修改Bean 的定义,Bean的类型,能做的事情比 BeanPostProcessor还多  (BeanDefinitionRegistryPostProcessor 集成自 BeanFactoryPostProcessor 接口)

 

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        //注册一个bean
        RootBeanDefinition beanDefinition = new RootBeanDefinition(MyGoods.class);
        //构造参数
        //ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
       // constructorArgumentValues.addIndexedArgumentValue(1, "user2");
       // beanDefinition.setConstructorArgumentValues(constructorArgumentValues);

        //添加 名字是 myDefinitionObject 的  BeanDifinition
        registry.registerBeanDefinition("myDefinitionObject",beanDefinition);

        //查找一个bean(所有的bean都可以在这里找到)
        System.out.println("有那些beanDefinition:"+ JSONObject.toJSONString( registry.getBeanDefinitionNames() )  );
        BeanDefinition myDefinitionObject = registry.getBeanDefinition("myDefinitionObject");


        //删除bean定义
        registry.removeBeanDefinition( "myDefinitionObject" );


        //在删除以后修改 myDefinitionObject 的 beanDifinition(类型都改了)
        RootBeanDefinition beanDefinition2 = new RootBeanDefinition(Goods.class);
        registry.registerBeanDefinition("myDefinitionObject",beanDefinition2);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

  

 

 

 

--------------------------------------------------------------------------------------------------------- 一些杂记------------------------------------------------------------------------------------------------------------------------

spring 的核心

  ioc (容器+工厂)
  aop ( 代理 + aspectj )

 

 

 

 

IOC 部分


ApplicationContext 的所有父接口都能干什么?


BeanFactory 的所有接口


BeanFactory ApplicationContext ,创建类实例的时间节点不一样?


xml 的 2种参数注入方式(set注入和 构造方法注入)


xml 向属实里面设置空值,特殊值,内部bean赋值,引用赋值,集合


spring xml p和 util 的namespan


FactoryBean 和 BeanFactory 区别,都是工厂类,前者是 spring的 bean 工厂,后者是spring 提供给我们实现工厂的接口


xml 通过 scope 可以设置 是单例还是多例(singleton,prototype),注解方式需要借助ObjectFactory 来得到多例


bena的生命周期 @PreDestroy,@PostConstruct ,@Bean(initMethod = "init", destroyMethod = "destroy") 在容器关闭的时候的顺序


BeanPostProcessor 里面 bean 的生命周期阶段监听函数


BeanPostProcessor 对所有 spring容器托管的bean都生效


@Resource ,@Autowired,@Qualifier ,Resource 可以指定 name ,Autowired 需要通过 Qualifier 指定名字,Resource 如果没有指定名字,那么变量名字优先,找不到会按照类型匹配,比Autowired 更加精确,所以有部分人推荐使用Resource


xml 方式 的 Autowire 支持 byType 和 byName 2种方式


xml 方式 通过 <context:property-placehoder location="文件.xml" >引入多个 xml 文件,神效时间是全程还是之前引入的才生效?


XMLApplicationContext 里面要使用注解需要 <context:component-scan base-package="">


xml 包扫描的 过滤器 使用自定义过滤器


spring 容器的生命周期接口函数 有哪些


spring纯注解方式使用的 AnnotationConfigApplicationContext 指定配置类来实现的


AOP 部分

 

spring AOP的 的 两种方式 ,动态代理(需要接口) 和 CGlib织入(修改源码)


JDK的 动态代理


AOP 的 5种切入类型


aspectj


https://blog.csdn.net/java_green_hand0909/article/details/90238242


xml 方式的 切面程序<aop:aspectj-autoproxy >


@Aspect 通过 @order 调整顺序


@EnableAspectjAutoProxy(proxyTargerClass=true)

    

 

posted on 2018-07-10 20:29  zhangyukun  阅读(142)  评论(0)    收藏  举报

导航