..

spring#注解知识巩固

 容器部分

通过 java的 vmoptions  可以通过设置-Dkey=value来覆盖系统的环境变量。

 


 

 

@Configuration注解。等价于之前的配置文件,注解在配置类上面。

 

@Conditional(WindowsCondition.class)注解。可以通过条件决定bean是否被加入容器中,这个注解中需要传入org.springframework.context.annotation.Condition这个接口的实现类,来作为判断依据的条件。

比如下面就是一个条件类的例子,这个类判断是否当前为windows环境:

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

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String s = conditionContext.getEnvironment().getProperty("os.name").toLowerCase();
        return s.startsWith("windows");
    }
}
View Code

 

@Import({Red.class,ColorImportSelector.class})注解。第三方包中无法在类上面添加@Component,@Service等注解,可以通过在配置类上面添加@Import({类名,类名})进行导入。

另外在@Import中还可以通过实现import org.springframework.context.annotation.ImportSelector;的类来导入一些bean到容器中,这个ImportSelector接口的selectImports方法返回的是需要被导入容器中的类名称。

 

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

public class ColorImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.haonan.transcactiontest.color.Green","com.haonan.transcactiontest.color.Blue"};
    }
}
View Code

 

在@Import中还可以通过实现org.springframework.context.annotation.ImportBeanDefinitionRegistrar;接口的类来手动的注册bean到容器中,比如通过如下代码:

import com.haonan.transcactiontest.color.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 ColorImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean red = registry.containsBeanDefinition("com.haonan.transcactiontest.color.Red");
        boolean blue = registry.containsBeanDefinition("com.haonan.transcactiontest.color.Blue");
        if(red && blue){
            RootBeanDefinition rainbow = new RootBeanDefinition(RainBow.class);
            registry.registerBeanDefinition("rainBow", rainbow);
        }
    }
}
View Code

 

 


关于BeanFactory:

在spring中实现org.springframework.beans.factory.FactoryBean这个接口得到一个FactoryBean,当把这个工厂注入到spring中,那么,通过applicationContext.getBean("工厂id"),

获取到的是FactoryBean生成的对象,而非工厂本身。如果需要活得工厂本身,需要用applicationContext.getBean("&工厂id");

////////////////////////////////////////////////////////////////////
//file1 工厂bean ColorFactoryBean.java
////////////////////////////////////////////////////////////////////
import org.springframework.beans.factory.FactoryBean;

public class ColorFactoryBean implements FactoryBean<Color> {

    @Override
    public Color getObject() throws Exception {
        System.out.println("ColorFactoryBean.getObject........");;
        return new Color();
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}
///////////////////////////////////////////////////////////////////////
// file2 配置类 MainConfig.java
///////////////////////////////////////////////////////////////////////
import com.haonan.transcactiontest.color.ColorFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MainConfig {
    
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        ColorFactoryBean colorFactoryBean = new ColorFactoryBean();
        return colorFactoryBean;
    }
}

///////////////////////////////////////////////////////////////////////
// file3 测试类 Test1.java
///////////////////////////////////////////////////////////////////////
package com.haonan.transcactiontest.test;

import com.haonan.transcactiontest.color.Color;
import com.haonan.transcactiontest.color.ColorFactoryBean;
import com.haonan.transcactiontest.config.MainConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Test1 {
    ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);

    @Test
    public void test1() {
        for (String name : app.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        Color color1 = (Color) app.getBean("colorFactoryBean");
        Color color2 = (Color) app.getBean("colorFactoryBean");
        ColorFactoryBean factory = (ColorFactoryBean) app.getBean("&colorFactoryBean");
        System.out.println(color1);
        System.out.println(color2);
        System.out.println(factory);
    }
}
View Code

 


bean的生命周期由容器管理(创建 ---初始化 ---销毁)

单实例:容器启动时候创建(可以通过@Lazy让实例懒加载,用的时候创建)

多实例:每次创建对象的时候创建(容器中的bean默认都是单实例,通过@Scope("prototype")让bean变成原型实例而非单实例)

方法一:

通过查看@Bean注解的定义可以看到可以在使用@Bean注解的时候通过initMethod,和destroyMethod来指定bean的初始化和销毁时候要执行的方法。

 

初始化方法调用时机(initMethod指定的):

  对象创建完成,并赋值好,调用初始化方法。

销毁方法调用时机(destroyMethod来指定):

  单实例:容器关闭的时候销毁

  多实例:容器不会管理这个bean,请自己销毁。

 

方法二:

通过让bean实现org.springframework.beans.factory.InitializingBean接口完成初始化逻辑

通过让bean实现org.springframework.beans.factory.DisposableBean接口实现销毁逻辑

 

方法三:

使用jsr250。

@PostConstruct注解的方法完成属性设置完成后的初始化逻辑

@PreDestroy注解的方法在容器移除bean之前,回调的销毁逻辑

 

方法四:

实现org.springframework.beans.factory.config.BeanPostProcessor接口,注意需要看这个接口中方法的注释活得更详细的信息。

BeanPostProcessor可以为所有bean进行设置。

 


 

关于BeanPostProcessor

//原理
populateBean(beanName,mbd,instanceWrapper);//给bean进行属性赋值
initializeBean{
    applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
    invokeInitMethods(beanName,wrappedBean,mbd);//执行自定义的初始(上面所述的三种)方法
    applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);
}
View Code

spring底层大量的使用了BeanPostProcessor接口

 

举例来说,任何实现了org.springframework.context.ApplicationContextAware接口的bean,都会在bean实例化并赋值属性后,执行applyBeanPostProcessorsBeforeInitialization时候,处理到ApplicationContextAwareProcessor时候(这个ApplicationContextAwareProcessor实现了BeanPostProcessor)。ApplicationContextAwareProcessor看当前bean是否实现了Aware,如果当前bean实现了Aware,就判断当前bean实现的是何种Aware,并注入。

 

再举例来说上述的@PostConstruct,@PreDestroy都是由InitDestroyAnnotationBeanPostProcessor这个BeanPostProcessor处理的。

 

再举例来说,处理@Autowired的AutowiredAnnotationBeanPostProcessor,也是由于(不只是)实现了BeanPostProcessor。


 

 

关于属性赋值:

@Value,

  • 可以使用"字面量,字符串,数字"
  • 可以使用SpEL,即#{20-2}
  • 可以使用环境变量(操作系统变量、配置文件、vmoption -Dkey=value),即${}

 至于使用${}加载配置文件的值,可以通过在配置类上面应用注解@PropertySource("classpath:配置文件名称.后缀名"),@PropertySource会把配置文件中定义的键值对保持到环境变量中去,这时候使用${}结合@Value就可以完成注入了。

 


 

 

自动装配

@Autowired(可以用在属性上,set方法上,构造器上,参数前)

  1.默认按照类型从容器中找组件;

  2.如果找到多个,就按照属性名称作为组件id去容器中查找;

  3.如果容器中存在多个同类型的组件,在使用@Autowired时候要加上@Qualifier("组件id")进行指定;

  4.@Autowired(required=false)避免找不到报错;

  5.如果容器中存在多个同类型的组件,可以使用@Primary指定某个组件是首选的,避免使用@Qualifier。

 

 @Resource

   属于jsr250,不支持@Primary,和对required=false

 

@Inject

  属于JSR330,和Autowired功能一样,但是不支持required=false

 


 

 

关于自定义组件想使用spring容器提供的默认组件,只需要实现XXXAware就可以了。

 

 


 

 

 AOP部分

 

AOP使用的三个步骤(注意业务组件要从容器中获得,否则直接new的实例不会被aop拦截):

  1. 将业务逻辑组件和切面类都加入容器中,并且告诉Spring哪个是切面类(@Aspect)
  2. 在切面类中的每一个通知方法上都标注通知注解,告诉Spring何时何地运行(@Pointcut,可抽取公共的切入点)
  3. 开启基于注解的aop模式(@EnableAspectJAutoProxy,注意springBoot引入相关starter后自动开启)

例子:

////////////////////////////////////////////
//文件1 MathCaculate.java业务组件类,单词好像写错了
///////////////////////////////////////////
package com.haonan.transcactiontest.service;

public class MathCaculate {
    public float div(float a, float b) {
        return a / b;
    }
}


////////////////////////////////////////////
//文件2 LogAspects.java 切面逻辑类
///////////////////////////////////////////
package com.haonan.transcactiontest.aop;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

@Aspect
public class LogAspects {

    @Pointcut("execution(public float com.haonan.transcactiontest.service.MathCaculate.*(..))")
    public void pointCut() {
        // 看吧,任意方法,加上@Pointcut可以定义共用的切入点
    }

    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        System.out.print("LogAspects.before args:");
        System.out.println(joinPoint.getSignature().getName() + "参数:" + Arrays.asList(args));
    }

    @After("execution(public float com.haonan.transcactiontest.service.MathCaculate.*(..))")
    public void logEnd(JoinPoint joinPoint) {
        System.out.print("LogAspects.logEnd:");
        System.out.println(joinPoint.getSignature().getName() + "运行结束");
    }

    /**
     * 可以以通过returing指定返回值,通过哪个参数传入切面的方法,需要注意的是,Joinpoint必须是第一参数
     *
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void logReturing(JoinPoint joinPoint, Object result) {
        System.out.print("LogAspects.logReturing:");
        System.out.println(joinPoint.getSignature().getName() + "返回:" + result);
    }

    /**
     * 可以以通过throwing指定异常值,通过哪个参数传入切面的方法,需要注意的是,Joinpoint必须是第一参数
     *
     * @param joinPoint
     * @param exception
     */
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void logException(JoinPoint joinPoint, Exception exception) {
        System.out.print("LogAspects.logException:");
        System.out.println(joinPoint.getSignature().getName() + "返回异常:" + exception);
    }
}



////////////////////////////////////////////
//文件3 AopConfig.java 配置类
///////////////////////////////////////////
package com.haonan.transcactiontest.config;

import com.haonan.transcactiontest.aop.LogAspects;
import com.haonan.transcactiontest.service.MathCaculate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy
@Configuration
public class AopConfig {
    @Bean
    public MathCaculate mathCaculate() {
        return new MathCaculate();
    }

    @Bean
    public LogAspects logAspects() {
        return new LogAspects();
    }
}



////////////////////////////////////////////
//文件4 AopTest.java测试类
///////////////////////////////////////////
package com.haonan.transcactiontest.test;

import com.haonan.transcactiontest.config.AopConfig;
import com.haonan.transcactiontest.service.MathCaculate;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AopTest {
    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(AopConfig.class);

    @Test
    public void test1(){
        //必须从容器中获取业务组件类,否则不会应用切面
        //组件的代理类,才会被切
        MathCaculate bean = app.getBean(MathCaculate.class);
        float result = bean.div(1f, 0f);
        System.out.println(result);
    }
}
View Code

 

 

 

 

 

 

 

placeholder
posted @ 2020-03-15 09:53  罗浩楠  阅读(174)  评论(0)    收藏  举报
..