ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring高级注解-Day2

2021-07-22 17:04:54  阅读:172  来源: 互联网

标签:java Spring Day2 指定 public bean dataSource 注解 class


学习目标

  • 学会Spring高级注解
  • 对应项目
    day3_anno_dependsOn
    day3_anno_lazy
    day3_anno_conditional
    day3_anno_profile
    day4_anno_basic
    day4_anno_jsr
    day4_anno_primary
    day4_anno_lifecycle

学习笔记

1 注入时机和设定注入条件的注解

1.1 @DependsOn

1.1.1 作用

  • 用于指定某个类的创建依赖的bean对象先创建。spring中没有特定bean的加载顺序,使用此注解则可指定bean的加载顺序。(在基于注解配置中,是按照类中方法的书写顺序决定的)

1.1.2 属性

  • value:用于指定bean的唯一标识。被指定的bean会在当前bean创建之前加载

1.1.3 基本使用

@Configuration
@ComponentScan("com.example")
public class SpringConfiguration {
}

SpringConfiguration.java

@Component
@DependsOn("eventListener")
public class EventSource {

    public EventSource(){
        System.out.println("事件源对象创建");
    }
}

EventSource.java

@Component
public class EventListener {

    public EventListener(){
        System.out.println("监听器创建");
    }
}

EventListener.java

public class SpringDependsOnTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("config");
        ac.start();
    }
}

SpringDependsOnTest.java

  • EventSource依赖于EventListener,所以先创建EventListener,后创建EventSource

1.2 @Lazy

1.2.1 作用

  • 用于指定单例bean对象的创建时机。在没有使用此注解时,单例bean的生命周期与容器相同。但是当使用了此注解之后,单例对象的创建时机变成了第一次使用时创建。注意:这不是延迟加载思想(因为不是每次使用时都创建,只是第一次创建的时机改变了)

1.2.2 属性

  • value: 指定是否采用延迟加载。默认值为true,表示开启

1.2.3 基本使用

@Configuration
@ComponentScan("com.example")
public class SpringConfiguration {
}

SpringConfiguration.java

@Component
@Lazy
public class LogUtil {
    public LogUtil(){
        System.out.println("LogUtil创建了");
    }
    public void printLog(){
        System.out.println("记录日志");
    }
}

LogUtil.java

public class SpringLazyTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("config");
        LogUtil logUtil = ac.getBean("logUtil", LogUtil.class);
        logUtil.printLog();
    }
}

SpringLazyTest.java

1.3 @Conditional

1.3.1 作用

  • 它的作用是根据条件选择注入的bean对象。

1.3.2 属性

  • value: 用于提供一个Condition接口的实现类,实现类中需要编写具体代码实现注入的条件。

1.3.3 基本使用

  • 自定义Condition实现bean的选择性注册
@Configuration
@Import(JdbcConfig.class)
@PropertySource({"classpath:jdbc.properties","classpath:linuxjdbc.properties"})
public class SpringConfiguration {
}

SpringConfiguration.java

/**
 * 自定义注册bean的条件,windows操作系统注入
 */
public class WindowsCondition implements Condition {
    /**
     * 是否注册到ioc容器中的和新方法
     *
     * @param conditionContext
     * @param annotatedTypeMetadata
     * @return 是true表示注册,否则不注册
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取ioc使用的BeanFactory对象
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = beanFactory.getBeanClassLoader();
        //获取环境信息,取出当前操作系统信息
        Environment environment = conditionContext.getEnvironment();
        //输出所有的系统环境信息
        if (environment instanceof StandardEnvironment) {
            //转换环境信息
            StandardEnvironment standardEnvironment = (StandardEnvironment) environment;
            Map<String, Object> map = standardEnvironment.getSystemEnvironment();
            for (Map.Entry<String, Object> me : map.entrySet()) {
                System.out.println(me.getKey() + " " + me.getValue());
            }
        }
        //获取bean定义信息的注册器
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        //获取当前系统的名称
        String os = environment.getProperty("os.name");
        //判断是否包含Windows规则
        if (os.contains("Windows")) {
            //需要注册到ioc容器
            return true;
        }
        //不需要注册到ioc容器
        return false;
    }
}

WindowsCondition.java

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取环境信息,取出当前操作系统信息
        Environment environment = conditionContext.getEnvironment();
        //获取当前系统的名称
        String os = environment.getProperty("os.name");
        //判断是否包含Windows规则
        if (os.contains("Linux")) {
            //需要注册到ioc容器
            return true;
        }
        //不需要注册到ioc容器
        return false;
    }
}

LinuxCondition.java

public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    /**
     * 创建windows系统测试的数据源
     * @return
     */
    @Bean("dataSource")
    @Conditional(WindowsCondition.class)
    public DataSource createWindowsDataSource(){
        //创建数据源
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        //给数据源填充属性
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        System.out.println("windows");
        return dataSource;
    }

    /**
     * 创建linux系统测试的数据源
     * @return
     */
    @Bean("dataSource")
    @Conditional(LinuxCondition.class)
    public DataSource createLinuxDataSource(@Value("${linuxjdbc.driver}") String linuxDriver,
                                       @Value("${linuxjdbc.url}") String linuxUrl,
                                       @Value("${linuxjdbc.username}") String linuxUsername,
                                       @Value("${linuxjdbc.password}") String linuxPassword){
        //创建数据源
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        //给数据源填充属性
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        System.out.println("linux");
        return dataSource;
    }
}

JdbcConfig.java

public class SpringConditionalTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("config");
        DataSource dataSource = ac.getBean("dataSource", DataSource.class);
        System.out.println(dataSource);
    }
}

SpringConditionalTest.java

1.4 @Profile

1.4.1 作用

  • @Profile注解是spring提供的一个用来标明当前运行环境的注解。我们正常开发的过程中经常遇到的问题是,开发环境是一套环境,测试是一套环境,线上部署又是一套环境。这样从开发到测试再到部署,会对程序中的配置修改多次,尤其是从测试到上线这个环节,让测试的也不敢保证改了哪个配置之后能不能在线上运行。为了解决上面的问题,我们一般会使用一种方法,就是针对不同的环境进行不同的配置,从而在不同的场景中跑我们的程序。
  • 而spring中的@Profile注解的作用就体现在这里。在spring使用DI来注入的时候,能够根据当前制定的运行环境来注入相应的bean。最常见的就是使用不同的DataSource了。

1.4.2 基本使用

@Configuration
@PropertySource("classpath:jdbc.properties")
@Import(JdbcConfig.class)
public class SpringConfiguration {
}

SpringConfiguration.java

public class JdbcConfig {

    @Value("${jdbc.driver}")
    private String driver;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    /**
     * 开发环境的数据源
     * @return
     */
    @Bean("dataSource")
    @Profile("dev")
    public DruidDataSource createDevDataSource(){
        //创建数据源对象
        DruidDataSource dataSource = new DruidDataSource();
        //设置属性
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        //开发环境的最大活动连接数
        dataSource.setMaxActive(5);

        return dataSource;
    }

    /**
     * 测试环境的数据源
     * @return
     */
    @Bean("dataSource")
    @Profile("test")
    public DruidDataSource createTestDataSource(){
        //创建数据源对象
        DruidDataSource dataSource = new DruidDataSource();
        //设置属性
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        //测试环境的最大活动连接数
        dataSource.setMaxActive(50);

        return dataSource;
    }

    /**
     * 生产环境的数据源
     * @return
     */
    @Bean("dataSource")
    @Profile("pro")
    public DruidDataSource createProDataSource(){
        //创建数据源对象
        DruidDataSource dataSource = new DruidDataSource();
        //设置属性
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        //生产环境的最大活动连接数
        dataSource.setMaxActive(150);

        return dataSource;
    }
}

JdbcConfig.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
@ActiveProfiles("pro")
public class SpringProfileTest {

    @Autowired
    private DruidDataSource druidDataSource;

    @Test
    public void testDataSource(){
        System.out.println(druidDataSource.getMaxActive());
    }
}

SpringProfileTest.java

2 用于创建对象的注解

2.1 @Component和三个衍生注解@Controller @Service @Repository

2.1.1 作用

  • 这四个注解都是用于修饰类的。是用于把当前类创建一个对象,存入spring的ioc容器中。在实例化时,首选默认无参构造函数。同时支持带参构造,前提是构造函数的参数依赖必须要有值。否则抛异常

2.1.2 属性

  • value:用于指定存入容器时bean的id。当不指定时,默认值为当前类的名称

3 用于注入数据的注解

3.1 @Autowired

3.1.1 作用

  • 自动按照类型注入。当ioc容器中有且只有一个类型匹配时可以直接注入成功。当有超过一个匹配时,则使用变量名称(写在方法上就是方法名称)作为bean的id,在符合类型的bean中再次匹配,能匹配上就可以注入成功。当匹配不上时,是否报错要看required属性的取值。

3.1.2 属性

  • required:是否必须注入成功。默认值是true,表示必须注入成功。当取值为true的时候,注入不成功会报错。

3.1.3 @Qualifier

3.1.3.1 作用
  • 当使用自动按类型注入时,遇到有多个类型匹配的时候,就可以使用此注解来明确注入哪个bean对象。注意它通常情况下都必须配置@Autowired注解一起使用
3.1.3.2 属性
  • value:用于指定bean的唯一标识。
3.1.3.3 问题
  • 必须要从容器中自动注入JdbcTemplate,否则在运行时会报空指针异常
@Autowired
private JdbcTemplate jdbcTemplate;
  • 自动注入的前提是JdbcTemplate已经注入到容器中
@Bean("jdbcTemplate")
public JdbcTemplate createJdbcTemplate(DataSource dataSource){
    return new JdbcTemplate(dataSource);
}
  • 如果容器中有多个JdbcTemplate,优先找到与变量名与Bean的id相匹配的注入,如果不匹配,则会因为在容器中找到多个JdbcTemplate而报错
  • 可以在@Autowired后使用@Qualifier指定唯一标识解决多个JdbcTemplate的问题

3.3 @Resource

3.3.1 作用

  • 此注解来源于JSR规范(Java Specification Requests),其作用是找到依赖的组件注入到应用来,它利用了JNDI(Java Naming and Directory Interface Java命名目录接口 J2EE规范之一)技术查找所需的资源。
    默认情况下,即所有属性都不指定,它默认按照byType的方式装配bean对象。如果指定了name,没有指定type,则采用byName。如果没有指定name,而是指定了type,则按照byType装配bean对象。当byName和byType都指定了,两个都会校验,有任何一个不符合条件就会报错。

3.3.2 属性

  • name:资源的JNDI名称。在spring的注入时,指定bean的唯一标识。
  • type:指定bean的类型。
  • lookup:引用指向的资源的名称。它可以使用全局JNDI名称链接到任何兼容的资源。
  • authenticationType:指定资源的身份验证类型。它只能为任何受支持类型的连接工厂的资源指定此选项,而不能为其他类型的资源指定此选项。
  • shareable:指定此资源是否可以在此组件和其他组件之间共享。
  • mappedName:指定资源的映射名称。
  • description:指定资源的描述。

3.3.3 基本使用

@Service
public class AccountServiceImpl implements AccountService {

    @Resource(type = AccountDao.class,name = "accountDaoImplOne")
    private AccountDao accountDao;

    @Override
    public void save() {
        accountDao.save();
    }
}

AccountServiceImpl.java

@Repository
public class AccountDaoImplOne implements AccountDao {
    @Override
    public void save() {
        System.out.println("1保存");
    }
}

AccountDaoImplOne.java

@Repository
public class AccountDaoImplTwo implements AccountDao {
    @Override
    public void save() {
        System.out.println("2保存");
    }
}

AccountDaoImplTwo.java

public class SpringJsrTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("config");
        AccountService accountService = ac.getBean("accountServiceImpl", AccountService.class);
        accountService.save();
    }
}

SpringJsrTest.java

3.4 @Inject

3.4.1 作用

  • 它也是用于建立依赖关系的。和@Resource和@Autowired的作用是一样,没有属性

3.4.2 基本使用

@Service
public class AccountServiceImpl implements AccountService {

    //@Resource(type = AccountDao.class,name = "accountDaoImplOne")
    @Inject
    @Named("accountDaoImplOne")
    private AccountDao accountDao;

    @Override
    public void save() {
        accountDao.save();
    }
}

AccountServiceImpl.java

3.5 几种注入数据注解的区别

  • @Autowired:来源于spring框架自身。
    默认是byType自动装配,当配合了@Qualifier注解之后,由@Qualifier实现byName装配。它有一个required属性,用于指定是否必须注入成功。
  • @Resource:来源于JSR-250规范。
    在没有指定name属性时是byType自动装配,当指定了name属性之后,采用byName方式自动装配。
  • @Inject:来源于JSR-330规范。(JSR330是Jcp给出的官方标准反向依赖注入规范。)
    它不支持任何属性,但是可以配合@Qualifier或者@Primary注解使用。
    同时,它默认是采用byType装配,当指定了JSR-330规范中的@Named注解之后,变成byName装配。

3.6 @Primary

3.6.1 作用

  • 用于指定bean的注入优先级。被@Primary修饰的bean对象优先注入,无属性

3.6.2 基本使用

  • 如果注入时没有指定名称,则优先使用@Primary注解的AccountDaoImplTwo
@Repository
@Primary
public class AccountDaoImplTwo implements AccountDao {
    @Override
    public void save() {
        System.out.println("2保存");
    }
}

AccountDaoImplTwo.java

4 和生命周期以及作用范围相关的注解

4.1 @Scope

4.1.1 作用

  • 用于指定bean对象的作用范围。

4.1.2 属性

  • value:指定作用范围的取值。在注解中默认值是""。
    但是在spring初始化容器时,会借助ConfigurableBeanFactory接口中的类成员:
    String SCOPE_SINGLETON = “singleton”;
  • scopeName:它和value的作用是一样的。
  • proxyMode:它是指定bean对象的代理方式的。指定的是ScopedProxyMode枚举的值
    DEFAULT:默认值。(就是NO)
    NO:不使用代理。
    INTERFACES:使用JDK官方的基于接口的代理。
    TARGET_CLASS:使用CGLIB基于目标类的子类创建代理对象。

4.2 @PostConstruct

4.2.1 作用

  • 用于指定bean对象的初始化方法。无属性

4.3 @PreDestroy

4.3.1 作用

  • 用于指定bean对象的销毁方法。无属性

4.3.2 基本使用

@Component
public class LogUtil {
    public LogUtil(){
        System.out.println("对象创建");
    }

    @PostConstruct
    public void init(){
        System.out.println("对象初始化");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("对象销毁");
    }
}

LogUtil.java

public class SpringLifecycleTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("config");
        LogUtil logUtil = ac.getBean("logUtil", LogUtil.class);
        System.out.println(logUtil);
        //关闭容器
        ac.close();
    }
}

SpringLifecycleTest.java

  • 对于单例会随着Spring容器的关闭销毁单例对象

标签:java,Spring,Day2,指定,public,bean,dataSource,注解,class
来源: https://blog.csdn.net/weixin_51628158/article/details/118967992

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有