这是一个小ioc框架, 主要是来测试我之前想的解决依赖的思路
功能写的比较少
public class MainTest {
public static void main(String[] args) {
Container.setLoggerLevel(Level.DEBUG);
var container = new EnhancedContainer(AppConfig.class);
container.getBean(SleepService.class).sleep();
}
}
已经上传到maven**仓库,复制下面的xml即可导入:
<dependency>
<groupId>io.github.cppsh1t</groupId>
<artifactId>crumbContainer</artifactId>
<version>0.1.10</version>
</dependency>
0.1.10之前的版本是使用cglib实现AOP,因为高版本JDK的兼容问题,需要加VM参数: --add-opens java.base/java.lang=ALL-UNNAMED
0.1.10之后替换成了Byte Buddy实现
用logback写了Logger,能看到依赖解决的过程,可以通过添加logback.xml修改,也可以通过下面的方法直接修改输出等级:
Container.setLoggerLevel(Level.DEBUG);
启动时会输出banner,在resources里写一个banner.txt应该可以改
Container container1 = new DefaultContainer(AppConfig.class);
Container container2 = new EnhancedContainer(AppConfig.class);
Container container2 = new AutoContainer(AppConfig.class);
Container container4 = MainContainer.getContainer();
//Container container4 = MainContainer.getContainer(DefaultContainer.class);
Container有3个实现,DefaultContainer使用我自己写的方法扫描Component,其他几个用的是ClassGraph库
AutoContainer的配置不需要@ComponentScan和@MapperScan,容器会自动从配置类的最顶级包名查找
MainContainer.getContainer()
会创建一个单例Container,并自动扫描到标记了MainConfiguraion
的注解的类当作配置类生成Container,
默认实现是AutoContainer,当使用以class作为参数的重载时,内部的Container就是参数的类型
用Bean标记方法将返回值注册为单例 如果想注册为其父类型,可以手动在Bean参数里指定,另外也可以通过name参数指定名字而非默认名字
@MainConfiguration
@ComponentScan("com")
@Configuration
@EnableAspectProxy
@MapperScan("com.mapper")
public class AppConfig {
@Bean(name = "retardName")
@Lazy
public String getName() {
return "Xqc";
}
@Bean
public int getInt() {
return new Random().nextInt(30);
}
}
Component和Bean基本一样
@Component
@Scope(ScopeType.PROTOTYPE)
public class Stone {
@Autowired
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
属性注入和spring不大一样,不需要给setter加Autowired,容器会自动寻找对应名字的setter,找不到再使用字段注入 在字段上进行注入时支持Autowired和Resource,一个是按类型,一个是按名字
相关的初始化接口和postProcessor和spring基本一样,postProcessor没写几个
可以使用Value注解注入外部值,默认是application.yaml,可以通过下面的方法增加或者修改默认路径,只支持yaml格式:
DefaultValuesFactory.setDefaultPath("defaultPath");
DefaultValuesFactory.addFilePath("newPath");
AOP和spring的API不大一样,使用AOP之前需要先将配置类加上EnableAspectProxy注解:
@ComponentScan("com")
@Configuration
@EnableAspectProxy
public class AppConfig {
@Bean
@Lazy
public String getName() {
return "Xqc";
}
}
AOP类需要加上Aspect注解,参数是要增强的类:
@Component
@Aspect(Foo.class)
public class FooAOP {
@Before("test")
public void before() {
System.out.println("before test");
}
@After("test")
public void after() {
System.out.println("after test");
}
@Around("toString")
public Object changeToString(JoinPoint joinPoint) {
return "bull shit";
}
}
要增强的方法标记上相关的注解,参数直接就是要增强的方法名
此外还有一些规则:
- Before和After需要是无参函数或者是单个参数类型为Object[], 为后者时会自动填充进原函数的参数
- AfterReturn需要参数类型和返回类型都为Object
- Around需要参数类型为JoinPoint,返回类型为Object,JoinPoint里有原函数的相关数据
整合了一点mybatis,写的很简单,只能进行一点简单的操作:
configClass:
@ComponentScan("com")
@Configuration
@EnableAspectProxy
@MapperScan("com.mapper")
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("username");
dataSource.setPassword("password");
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean;
}
}
getMapper:
public class MainTest {
public static void main(String[] args) {
var container = new EnhancedContainer(AppConfig.class);
var mapper = container.getBean(TestMapper.class);
mapper.selectStudents().forEach(System.out::println);
}
}