执行顺序
BeanFactoryPostProcessor —> 普通Bean构造方法 —> 设置依赖或属性 —> @PostConstruct —> InitializingBean —> initMethod
此案例是 将配置文件里的一些敏感数据进行加密后,启动项目后,spring容器会优先执行 BeanFactoryPostProcessor 子类流程,在子类流程中再将敏感数据进行解密,起到保密的效果
一、正常mvc流程
1、entity
@Data
public class Person {
private Integer id;
private String name;
private Integer age;
}
2、controller
@RestController
public class PersonController {
@Autowired
private PersonService personService;
@GetMapping("/person")
public List<Person> selectAll(){
List<Person> persons = this.personService.selectPersons();
return persons;
}
}
3、service
public interface PersonService {
List<Person> selectPersons();
}
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonMapper personMapper;
@Override
public List<Person> selectPersons() {
List<Person> persons = this.personMapper.selectPersons();
return persons;
}
}
4、mapper
@Mapper
@Repository
public interface PersonMapper {
List<Person> selectPersons();
}
5、mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lian.beanfactorypostprocessor.mapper.PersonMapper">
<select id="listPerson" resultType="com.lian.beanfactorypostprocessor.entity.Person">
SELECT
id,name,age
FROM
person
</select>
<select id="selectPersons" resultType="com.lian.beanfactorypostprocessor.entity.Person">
SELECT
id,name,age
FROM
person
</select>
</mapper>
6、yml
server:
port: 8888
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/websocketone?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone = GMT
username: root
# root加密后的密码
password: GQlo/lcKiXIEqDtzF3Ds2w==
mybatis:
mapper-locations: classpath:mapper/*.xml
7、扫描spring bean
@ComponentScan(basePackages = {"com.lian"})
@Configuration
public class Configurator {
}
二、BeanFactoryPostProcessor子类
1、加解密
//加解密类
public class EnDeCode {
private static final String ALGRITHM_SHA1PRNG = "SHA1PRNG";
private static final String KEY_SHA = "AES";
//加密
public static String encode(String context,String secretKey) throws Exception{
Key key = getKey(secretKey);
Cipher cipher = Cipher.getInstance(KEY_SHA);
cipher.init(Cipher.ENCRYPT_MODE,key);
byte[] bytes = cipher.doFinal(context.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
String encode = encoder.encode(bytes);
return encode;
}
//解密
public static String decode(String context, String secretKey) throws Exception{
Key key = getKey(secretKey);
Cipher cipher = Cipher.getInstance(KEY_SHA);
cipher.init(Cipher.DECRYPT_MODE,key);
BASE64Decoder decoder = new BASE64Decoder();
byte[] bytes = decoder.decodeBuffer(context);
byte[] aFinal = cipher.doFinal(bytes);
String res = new String(aFinal);
return res;
}
//获取key
public static Key getKey(String secretKey) throws Exception{
SecureRandom secureRandom = SecureRandom.getInstance(ALGRITHM_SHA1PRNG);
secureRandom.setSeed(secretKey.getBytes());
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_SHA);
keyGenerator.init(secureRandom);
SecretKey key = keyGenerator.generateKey();
return key;
}
public static void main(String[] args) throws Exception {
//加密
String encode = encode("root", KEY_SHA);
System.out.println("encode : "+encode); //GQlo/lcKiXIEqDtzF3Ds2w==
//解密
String decode = decode("GQlo/lcKiXIEqDtzF3Ds2w==", KEY_SHA);
System.out.println("decode : "+decode);
}
}
2、BeanFactoryPostProcessor子类实现
@Component
public class DefineBeanFactory implements EnvironmentAware, BeanFactoryPostProcessor {
private static final String KEY_SHA = "AES";
private ConfigurableEnvironment configurableEnvironment;
@Override
public void setEnvironment(Environment environment) {
this.configurableEnvironment = (ConfigurableEnvironment)environment;
}
//spring容器会先走此方法流程,再去初始化其他的bean
//ConfigurableListableBeanFactory 此子类拥有父类的几十个方法,是beanFactory的主要子类
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
MutablePropertySources propertySources = configurableEnvironment.getPropertySources();
List<PropertySource<LinkedHashMap>> mapList = StreamSupport.stream(propertySources.spliterator(), false)
.filter(o -> o instanceof OriginTrackedMapPropertySource)
.map(s -> (PropertySource<LinkedHashMap>) s)
.collect(Collectors.toList());
for (PropertySource<LinkedHashMap> source : mapList) {
LinkedHashMap map = source.getSource();
try {
if (map.containsKey("spring.datasource.druid.password")){
String value = String.valueOf(map.get("spring.datasource.druid.password"));
//解密
String decodePassword = EnDeCode.decode(value, KEY_SHA);
map.put("spring.datasource.druid.password",decodePassword);
}else {
continue;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}