Jar-IOC-DI:别人包里的对象就不能注入了吗?
JAR-IOC-DI
搓炸包
先弄一个空的Maven项目
- 注意JDK版本,项目中的有些API不支持过旧的或者过新的Java版本
- 骨架选择quickStart,理论上其他骨架也能行,但是咸鱼只试过这一个骨架
在空项目中编辑配置文件
其他的已经搓腻了,这次搓炸包注意build
标签中的内容:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifestEntries>
<!-- 此处写主类的全限定类名 -->
<Main-Class>club.saltfish.App</Main-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
这样的配置可以配合Maven构建一个炸包,在有Java环境的计算机中双击炸包可以从主类开始运行。
另附把Jar包安装到本地Maven仓库的指令:
mvn install:install-file -Dfile=炸包路径.jar -DgroupId=club.saltfish -DartifactId=组件名 -Dversion=1.0 -Dpackaging=jar
导入Maven项目中
按照常规的导入项目依赖的方式就可以了
<dependency>
<groupId>club.saltfish</groupId>
<artifactId>common-pojo</artifactId>
<version>1.0</version>
</dependency>
一般写完artifactID之后,其余配置项都自动补充了。
将炸包中的对象注入到容器中
首先,依赖中的Jar包都是只读属性(不允许编辑),所以给依赖中的Jar包添加@Component
之类的注解来完成注入是不现实的。
玩法一:@Bean
假设一个炸包中有如下结构:
└─club └─saltfish ├─config │ CommonConfig.java │ └─pojo Country.java Province.java
那么在一个配置类(@Configuration
)中,写一个调用构造器的方法:
@Bean
public Country country(){
return new Country(); ;
}
就可以利用一个@Bean
注解把这个对象丢进IOC容器里,在容器中,这个对象的引用是country
,即方法名。
配置类必须在启动类所在包及其子包中。
@Bean
注解中课添加参数:该类在容器中的名称。
依赖注入
这个简单,只需要在方法形参中添加对应的对象就行。
//对象默认的名字是: 方法名
//@Bean("aa")
//如果方法的内部需要使用到ioc容器中已经存在的bean对象,那么只需要在方法上声明即可,spring会自动的注入
@Bean
public Province province(Country country){
return new Province();
}
同理,我们可以在调用构造器的时候直接给它初始化掉,或者注入依赖:
@Bean
//假设我们已经在IOC容器中注入了一个User对象
public Country Country(User user){
Country country = new Country;
country.setName("China");//初始化成员
country.setLocation("Asia");//初始化成员
country.setUser(user);//依赖注入
return province;
}
甚至可以在application
配置文件中(以yml为例)配置一个类的成员属性值:
country:
name: China
location: Aisa
user:
name: saltfish
age: 90
health: dying
在注入的时候就需要:
@Configuration
@ConfigurationProperties(prefix = "country")
public class Commonconfig {
@Bean
//假设我们已经在IOC容器中注入了一个User对象
public Country country(){
Country country = new Country(@Value("${name}")String name,@Value("${location}")String location,User user);
//初始化User略,也是@Value
return new Country(name,value,user)
}
}
用配置初始化普通类,同理。
玩法二:@import
在启动类上添加注解@Import(配置类.class)
,即可注入配置类中注入的对象。
@Import('Configuration.class')
@SpringBootApplication
public class LearnMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(LearnMybatisApplication.class, args);
}
}
路径从根包开始数。
也可以一次性传入很多个配置类(配置类数组):
@Import({Configuration1.class,Configuration2.class,Configuration3.class,})
@SpringBootApplication
public class LearnMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(LearnMybatisApplication.class, args);
}
}
但是这样并不优雅简洁。我们可以使用另一个类专门负责统筹配置类:
使用ImportSelector
接口
public class CommonImportSelector implements ImportSelector {
@Override//重写方法,
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//返回的字符串的值是配置类的全限定类名
return new String[]{"club.saltfish.config.Configuration1.class","club.saltfish.config.Configuration2.class","club.saltfish.config.Configuration3.class",}
}
然后在启动类中:
@Import(CommonImportSelector.class)
@SpringBootApplication
public class LearnMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(LearnMybatisApplication.class, args);
}
}
读取配置文件注入
先写一个配置文件:
club.saltfish.config.Commonfig
这个配置文件每一行只写一个类的全限定类名。
这个配置文件是任意格式的文本,需要用Stream读取:
public class CommonImportSelector implements ImportSelector {
@Override//重写方法,
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//读取配置文件的内容
List<String> imports = new ArrayList<>();
InputStream is = CommonImportSelector.class.getClassLoader().getResourceAsStream("上述配置文件路径");//开一个流读取
BufferedReader br = new BufferedReader(new InputStreamReader(is));//buffer封装
String line = null;
while((line = br.readLine())!=null){
imports.add(line);//循环读取每一行,即每个类
}
is.close();
return imports.toArray(new String[0]);
}
其中Stream读取文件可能引发异常,为保证代码简洁容易理解,不做异常处理,请自行try-catch。
组合技:自己搓注解
自定义注解:
新建一个注解
(@Interface
),添加两个源注解:
@Target(ElementType.TYPE)//源注解一:表示定义的注解是类级注解
@Retention(RetentionPolicy.RUNTIME)//源注解二:表示注解会保留到运行时
@Import(CommonImportSelector.class)//之前的注解:导入Selector
public @interface EnableCommonConfig {
}
接口中不用写任何东西,直接在启动类中添加自己做的注解:
@SpringBootApplication
@EnableCommonConfig
@ComponentScan("club.saltfish")
public class SpringbootRegisterApplication {
public static void main(String[] args){
SpringApplication.run(SpringbootRegisterApplication.class, args);
}
}
就完事了。
感觉自定义注解能干大事,但是才疏学浅,压根不会。浅浅找了些资料去了解如何能写一些代码,去操作注解过的对象或者方法。似乎是需要用到Java的反射机制
,能在运行时(RUNTIME)动态的“玩弄”对象。但是看起来是个很深奥、底层、复杂的知识系统,先不打算拿下它。留待彻底玩明白Spring系列后再来淦它。