栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring(二) 条件注解(@Profile原理即使用场景案例)+db. properties 配置文件的注入以及原理+xml的包扫描(官方推荐与日常注入)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring(二) 条件注解(@Profile原理即使用场景案例)+db. properties 配置文件的注入以及原理+xml的包扫描(官方推荐与日常注入)

一.条件注解: 1.1 使用场景

项目中的多环境配置

  • ​ springBoot的自动化配置
  • ​ 项目中的多环境配置
  • 理解:条件注解是多环境配置的核心,思路就是提前准备好环境,所谓的环境,实际上就是Condition接口的实现类,然后在注册Bean的时候,通过@Conditional注解去指定环境,当满足某种条件的时候,bean才会注入到Spring容器中。
二.多环境的切换

ps: 提前准备好生产环境,开发环境等的配置信息,将来通过Profile可以一键切换。

2.1 @Profile 的底层理解–@Conditional 条件注解(扩充)

​ 因为环境切换是十分常见的需求,所以java有对应的注解@Profile,我们通过这个注解去实现多环境的切换。这个注解的本质就是@Conditional 条件注解,通道的条件实际上就是ProfileCondition

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

	
	String[] value();

}

条件注解:

class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取 Profile 注解的所有属性,其实这个注解只有一个 value 属性,属性的值是一个数组
		MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if (attrs != null) {
            //将属性中的 value 读取出来,这个 value 的值实际上是一个 String 数组,遍历 String 数组
			for (Object value : attrs.get("value")) {
                //判断当前环境中,有没有 value 中的值
				if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
					return true;
				}
			}
			return false;
		}
		return true;
	}

}
2.2 多环境切换通过java代码的实现

具体实现:

2.2.1 定义一个DataSource:
public class DataSource {
    private String url;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "DataSource{" +
                "url='" + url + ''' +
                ", username='" + username + ''' +
                ", password='" + password + ''' +
                '}';
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
2.2.2 配置开发/生产环境的数据源JavaConfig
@Configuration
public class JavaConfig {
    
    @Profile("dev")
    @Bean("ds")
    DataSource devDataSource() {
        DataSource ds = new DataSource();
        ds.setUsername("root");
        ds.setPassword("123");
        ds.setUrl("jdbc:mysql:///test01");
        return ds;
    }

    
    @Profile("prod")
    @Bean("ds")
    DataSource prodDataSource() {
        DataSource ds = new DataSource();
        ds.setUsername("zhangsan");
        ds.setPassword("jdfkslajfl890324");
        ds.setUrl("jdbc:mysql://114.132.43.22/prod01");
        return ds;
    }
}

注册Bean的时候,通过@Profile(“prod”)注解来指定当前Bean在那个环境下生效。当启动容器的时候,要为Spring容器指定当前的环境信息。

2.2.3 最后,加载配置类,先配置当前的环境,再去加载配置类(同理,xml配置方法也是一样的)
public class Demo01 {
    public static void main(String[] args) {
        //注意先不要写配置类,要先设置环境信息
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        //设置当前的环境信息
        ctx.getEnvironment().addActiveProfile("prod");
        ctx.register(JavaConfig.class);
        ctx.refresh();
        DataSource ds = ctx.getBean(DataSource.class);
        System.out.println("ds = " + ds);
    }
}
2.3 通过xml配置文件实现(第一步,第二步与java配置方法一样) 2.3. 1定义一个dasource 2.3.2 配置开发/生产环境的数据 2.3.3 xml中加 载配置

首先在xml文件中,通过beans标签来指定环境:




    
        
        
            
            
            
        
    
    
        
        
            
            
            
        
    

将来Spring容器启动的时候,会根据当前的环境信息去注册不同的beans标签中的Bean。

启动容器的时候,设置一下当前环境即可:

public class Demo02 {
    public static void main(String[] args) {
        //先不要加载配置文件
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
        ctx.getEnvironment().addActiveProfile("dev");
        //设置好当前环境之后,再去设置配置文件的位置
        ctx.setConfigLocation("applicationContext.xml");
        ctx.refresh();
        DataSource ds = ctx.getBean(DataSource.class);
        System.out.println("ds = " + ds);
    }
}
三.db. properties 配置文件的注入 3.1 db.properties 配置文件的作用

连接池配置文件db.properties是java中采用数据库连接池技术完成应用对数据库的操作的配置文件信息的文件。具体配置项目如下:

3.2 java代码中的配置

Dsconfig

@Configuration
//1.把db.properties注入到spring容器中
//注意:classpath要全部小写
@PropertySource("classpath:db.properties")
public class DsConfig {

   
   @Value("${db.username}")
   String username;
   @Value("${db.password}")
   String password;
   @Value("${db.url}")
   String url;

   
   //官方推荐构造区注入
   @Bean
   DataSource dataSource() {
       DataSource ds = new DataSource();
       ds.setPassword(password);
       ds.setUsername(username);
       ds.setUrl(url);
       return ds;
   }
}

resources包下的db.porperties的配置

db.url=jdbc:mysql://localhost:3306/takeaway?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
db.username=root
db.password=root

测试类 Demo3

        //1.写入配置类
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(DsConfig.class);
        //2.写入实体类
        DataSource bean = annotationConfigApplicationContext.getBean(DataSource.class);
        System.out.println("bean = " + bean);
        

注意:
  • 要通过spring容器的ioc自动的的把bean装配到spring容器中才可以通过@Value 注解拿到,bean对象存储在spring容器中的属性字符串

  • 如果自己手动new 了一个Bean对象,spring容器是不会给他装配的,我们没办法通过@Value注解拿到这个新new 的对象所对应的属性字符串,控制面板会显示为null

    测试类:

    Demo03

    package com.huang.demo.p3;
    
    import com.huang.demo.p1.model.DataSource;
    
    public class Demo03 {
        public static void main(String[] args) {
            
            DataSource dataSource = new DsConfig().dataSource();
            System.out.println("dataSource = " + dataSource);
        }
    }
    
    

    控制台显示图:

3.3 xml中的配置

connect.xml




    
    
    
    db.url}, 表示引用 Spring 容器中,key 为 db.url 的变量。
  		2.1 把DataSource打入Spring容器
  		2.2 把DataSource和db.properties的属性接口打通,方便以后直接把数据库的数据从db.properties中拿到DataSource这个实体类中
    -->
    
        
        
        
    

测试方法:

Demo03

  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
        ctx.getEnvironment().addActiveProfile("dev");
        ctx.refresh();
        DataSource ds = ctx.getBean(DataSource.class);
        System.out.println("ds = " + ds);
四.xml配置包扫描


    
        


4.1 之前的Bean注册方式
  • 一个个注册
  • 十分繁琐
4.2 Java配置包扫描:官方推荐 4.2.1 官方推荐步骤

整体上来说,分为三个方面:

第一方面 : 将 Bean 注册到 Spring 容器中:@Repository、@Service、@Controller 以及 @Component。

@Repository
public class UserDao {
    public User getUserByUsername(String username) {
        User user = new User();
        user.setUsername(username);
        user.setAddress("广州");
        return user;
    }
}

第二方面:

@Service
public class UserService {
    UserDao userDao;

    
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User getUserById(String username) {
        return userDao.getUserByUsername(username);
    }

}

这里就出现了问题了,如果有多个构造器怎么办,即userService的有参和无参构造器要是同时存在,会发生什么问题,我们怎么解决这个问题?

即UserService中出现了

有参构造无参构造器同时存在会报错


@Service
public class UserService {
    UserDao userDao;

    //无参构造器
    public UserService() {
    }

    //有参构造器
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User getUserById(String username) {
        return userDao.getUserByUsername(username);
    }

}

报错空指针异常

  • 说了UserService中的32行找不到getUserId
  • 有参构造没有高亮即没有被调用
  • 上面两个推断出了这时候调用的构造器是无参构造器,即这时候没有办法区分用哪个构造器,idear默认去使用了无参构造

如何解决: 加上

  • @Autowired 注解可解决
  • @Autowired 表示根据类型去 Spring 容器中查找到相应的 Bean,并赋值给 userService 变量

即userservice这么写

@Service
public class UserService {
    UserDao userDao;

    
    public UserService() {
    }
    
    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User getUserById(String username) {
        return userDao.getUserByUsername(username);
    }

}

补充:如何用注解注入spring容器?

@ComponentScan(basePackages = "com.qfedu.demo")
@Configuration
public class JavaConfig {
}

通过 @ComponentScan 注解指定组件的路径即可。

4.2.2 日常使用较多的写法

和前面的步骤相比,主要是第二步不一样,其他都是一样的。

@Controller
public class UserServlet {
   
    @Autowired
    UserService userService;

    public User getUserById(String username) {
        return userService.getUserById(username);
    }
}

直接在属性上添加 @Autowired 注解就可以完成属性的注入了。

这种写法是我们在实际开发中使用较多的一种方式。

4.2.3 为什么使用官方推荐构造方法注入:
  • 这个类将来不一定注入进了spring容器,也有可能是外部的Bean对象

  • 或者是我们自己临时new 出来的userServlet对象,如果是用户new出来的这个时候其中的userService的变量就位null。

  • 而如果是用户直接new 一个UserService 实例的话,就必须传递一个UserDao 的实例

  • 核心思想:这个Bean我可以去spring容器里面拿(注入进了spring容器的话),而如果我们需要弄出来一个我们需要的且Spring容器没有注入的也十分的方便。

  • 但是大部分情况下,一个类的属性非常多,导致我们使用构造方法注入要写的构造方法长的一笔,麻烦,所以用的少

serServlet {

@Autowired
UserService userService;

public User getUserById(String username) {
    return userService.getUserById(username);
}

直接在属性上添加 @Autowired 注解就可以完成属性的注入了。

这种写法是我们在实际开发中使用较多的一种方式。

4.2.3 为什么使用官方推荐构造方法注入:
  • 这个类将来不一定注入进了spring容器,也有可能是外部的Bean对象

  • 或者是我们自己临时new 出来的userServlet对象,如果是用户new出来的这个时候其中的userService的变量就位null。

  • 而如果是用户直接new 一个UserService 实例的话,就必须传递一个UserDao 的实例

  • 核心思想:这个Bean我可以去spring容器里面拿(注入进了spring容器的话),而如果我们需要弄出来一个我们需要的且Spring容器没有注入的也十分的方便。

  • 但是大部分情况下,一个类的属性非常多,导致我们使用构造方法注入要写的构造方法长的一笔,麻烦,所以用的少

    而注解注入的方式十分的简单

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/999481.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号