spring4 知识点

 

1 bean的 创建

 


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

    @Bean还可以写在枚举上面


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

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

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

    

  

    


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

    

1
2
3
4
5
6
@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 指定的

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

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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") 类指定注入实例的名字

  

1
2
3
@Autowired
@Qualifier("getGood1")
Goods goods;

  

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

 

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

 

 

 

 

 

4  spring的多例

 

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

 

1
2
3
4
5
6
7
8
9
10
//--------------------------------@Scope的 多例---------------------------------------------------------
 
    int i = 0;
    @Bean
    @Scope("prototype")
    public Goods getScopeGoods() throws Exception {
        Goods goods = Goods.randomGoods();
        goods.setName("getScopeGoods" + i++);
        return goods;
    }

 

 

    获取多例有2种办法

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

    

1
2
3
4
5
6
7
8
9
/**
 * 通过 @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 获取(注解方式需要用这种)

  

1
2
3
4
5
6
7
8
9
10
@Autowired
ObjectFactory<Goods> getScopeGoods;
 
/**
 * 通过ObjectFactory获取多例对象
 */
@Test
public void t6(){
    System.out.println( getScopeGoods.getObject() );;
}

  

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

  比如这样:

1
2
3
@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参数形参注入(貌似会循环注入)

1
2
3
4
5
6
//--------------------------------@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;
}
}

  

测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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

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

1
2
3
@Autowired
 
ObjectFactory<单例对象类型> 单例对象工厂;

  

 


  

8 几个重要的 postProcessor 接口 

    BeanPostProcessor ,BeanFactoryPostProcessor ,BeanDefinitionRegistryPostProcessor 

    执行顺序  BeanDefinitionRegistryPostProcessor >BeanFactoryPostProcessor  >BeanPostProcessor 

 

  

 1  BeanPostProcessor

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

 

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

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

    

   

一个修改 goods 属性的 BeanPostProcessor 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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个)

1
2
3
4
5
6
7
8
/**
 * 测试 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  执行的时候就不会在初始化这个类了(认为已经初始化完成)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@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 接口)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@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   zhangyukun  阅读(135)  评论(0编辑  收藏  举报

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示