问题:

如果我们想给UserService注入HikariDataSource,但是这个类位于com.zaxxer.hikari包中,并且HikariDataSource也不可能有@Component注解,如何告诉IoC容器创建并配置HikariDataSource?或者换个说法,如何创建并配置一个第三方Bean?

源码如下:

User

package com.sun.bean;

/**
 * @Auther Mario
 * @Date 2021-02-23 15:50
 * @Version 1.0
 * @description
 */
public class User {

    private long id;
    private String email;
    private String password;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User(long id, String email, String password, String name) {
        this.id = id;
        this.email = email;
        this.password = password;
        this.name = name;
    }
}

MailService

package com.sun.service;

import com.sun.bean.User;
import org.springframework.stereotype.Component;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @Auther Mario
 * @Date 2021-02-23 15:47
 * @Version 1.0
 * @description
 */
@Component
public class MailService {
    private ZoneId zoneId = ZoneId.systemDefault();

    public void setZoneId(ZoneId zoneId){
        this.zoneId = zoneId;
    }

    public String getTime(){
        return ZonedDateTime.now(this.zoneId).format(DateTimeFormatter.ISO_ZONED_DATE_TIME);
    }

    public void sendLoginMail(User user){
        System.err.println(String.format("Hi, %s! You are logged in at %s",
                user.getName(),getTime()));
    }

    public void sendRegistrationMail(User user){
        System.out.println(String.format("Welcome, %s",user.getName()));
    }
}

UserService

package com.sun.service;

import com.sun.bean.User;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Auther Mario
 * @Date 2021-02-23 15:55
 * @Version 1.0
 * @description
 */
@Component
public class UserService {

    @Autowired
    private MailService mailService;
    @Autowired
    private HikariDataSource dataSource;

    public void setMailService(MailService mailService) {
        this.mailService = mailService;
    }

    private List<User> users = new ArrayList<>(List.of(
            new User(1, "bob@example.com", "password", "Bob"), // bob
            new User(2, "alice@example.com", "password", "Alice"), // alice
            new User(3, "tom@example.com", "password", "Tom"))); // tom

    public User login(String email, String password) throws SQLException, SSLException {
//        for (User user : users) {
//            if (user.getEmail().equalsIgnoreCase(email) && user.getPassword().equals(password)) {
//                mailService.sendLoginMail(user);
//                return user;
//            }
//        }
        try (Connection conn = dataSource.getConnection()){
            try(PreparedStatement ps = conn.prepareStatement("select * from user")){
                try(ResultSet rs = ps.executeQuery()){
                    while(rs.next()) {
                        Long dbId = rs.getLong("id");
                        String dbEmail = rs.getString("email");
                        String dbPassword = rs.getString("password");
                        String dbName = rs.getString("name");
                        if(dbEmail.equals(email) && dbPassword.equals(password)) {
                            return new User(dbId, dbEmail, dbPassword, dbName);
                        }
                    }
                    throw new RuntimeException("login failed.");
                }
            }
        }
//        throw new RuntimeException("login failed.");
    }



    //查找id
    public User getUser(long id){
        return this.users.stream().filter(user -> user.getId() == id).
                findFirst().orElseThrow();
    }

    //注册
    public User register(String email,String password,String name){
        users.forEach((user) -> {
            if(user.getEmail().equalsIgnoreCase(email)){
                throw new RuntimeException("email exist");
            }
        });
        User user = new User(users.stream().mapToLong(u -> u.getId()).max().getAsLong() + 1,
                email,password,name);
        users.add(user);
        mailService.sendRegistrationMail(user);
        return user;
    }


}

package com.sun;

import com.sun.bean.User;
import com.sun.service.UserService;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLException;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @Auther Mario
 * @Date 2021-02-24 10:29
 * @Version 1.0
 * @description
 */
@Configuration
@ComponentScan
public class AppConfig {

    public static void main(String[] args) throws SQLException, SSLException {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = (UserService) ctx.getBean("userService");
        User user = userService.login("bob@example.com", "password");
        User mario = new User(4,"mario@sina.com","12345","mario");
        userService.register(mario.getEmail(),mario.getPassword(),mario.getName());
        System.out.println(user.getName());
    }

    //使用第三方Bean
    @Bean(name = "dataSource")
    public HikariDataSource getDataSource(){
        Properties props = new Properties();
        props.setProperty("jdbcUrl","jdbc:mysql://localhost:3306/springIoc?characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false");
        props.setProperty("username","root");
        props.setProperty("password","1234");
        HikariConfig config = new HikariConfig(props);
        config.addDataSourceProperty("cachePrepStmts", "true");
        HikariDataSource dataSource = new HikariDataSource(config);
        return dataSource;
    }
}