Initial project
This commit is contained in:
128
.gitignore
vendored
128
.gitignore
vendored
@ -1,98 +1,38 @@
|
|||||||
# ---> JetBrains
|
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
||||||
|
|
||||||
# User-specific stuff
|
|
||||||
.idea/**/workspace.xml
|
|
||||||
.idea/**/tasks.xml
|
|
||||||
.idea/**/usage.statistics.xml
|
|
||||||
.idea/**/dictionaries
|
|
||||||
.idea/**/shelf
|
|
||||||
|
|
||||||
# AWS User-specific
|
|
||||||
.idea/**/aws.xml
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
.idea/**/contentModel.xml
|
|
||||||
|
|
||||||
# Sensitive or high-churn files
|
|
||||||
.idea/**/dataSources/
|
|
||||||
.idea/**/dataSources.ids
|
|
||||||
.idea/**/dataSources.local.xml
|
|
||||||
.idea/**/sqlDataSources.xml
|
|
||||||
.idea/**/dynamic.xml
|
|
||||||
.idea/**/uiDesigner.xml
|
|
||||||
.idea/**/dbnavigator.xml
|
|
||||||
|
|
||||||
# Gradle
|
|
||||||
.idea/**/gradle.xml
|
|
||||||
.idea/**/libraries
|
|
||||||
|
|
||||||
# Gradle and Maven with auto-import
|
|
||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
|
||||||
# auto-import.
|
|
||||||
# .idea/artifacts
|
|
||||||
# .idea/compiler.xml
|
|
||||||
# .idea/jarRepositories.xml
|
|
||||||
# .idea/modules.xml
|
|
||||||
# .idea/*.iml
|
|
||||||
# .idea/modules
|
|
||||||
# *.iml
|
|
||||||
# *.ipr
|
|
||||||
|
|
||||||
# CMake
|
|
||||||
cmake-build-*/
|
|
||||||
|
|
||||||
# Mongo Explorer plugin
|
|
||||||
.idea/**/mongoSettings.xml
|
|
||||||
|
|
||||||
# File-based project format
|
|
||||||
*.iws
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
out/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
|
||||||
.idea_modules/
|
|
||||||
|
|
||||||
# JIRA plugin
|
|
||||||
atlassian-ide-plugin.xml
|
|
||||||
|
|
||||||
# Cursive Clojure plugin
|
|
||||||
.idea/replstate.xml
|
|
||||||
|
|
||||||
# SonarLint plugin
|
|
||||||
.idea/sonarlint/
|
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
||||||
com_crashlytics_export_strings.xml
|
|
||||||
crashlytics.properties
|
|
||||||
crashlytics-build.properties
|
|
||||||
fabric.properties
|
|
||||||
|
|
||||||
# Editor-based Rest Client
|
|
||||||
.idea/httpRequests
|
|
||||||
|
|
||||||
# Android studio 3.1+ serialized cache file
|
|
||||||
.idea/caches/build_file_checksums.ser
|
|
||||||
|
|
||||||
# ---> Maven
|
|
||||||
target/
|
target/
|
||||||
pom.xml.tag
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
pom.xml.releaseBackup
|
!**/src/main/**/target/
|
||||||
pom.xml.versionsBackup
|
!**/src/test/**/target/
|
||||||
pom.xml.next
|
|
||||||
release.properties
|
|
||||||
dependency-reduced-pom.xml
|
|
||||||
buildNumber.properties
|
|
||||||
.mvn/timing.properties
|
|
||||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
|
||||||
.mvn/wrapper/maven-wrapper.jar
|
|
||||||
|
|
||||||
# Eclipse m2e generated files
|
### IntelliJ IDEA ###
|
||||||
# Eclipse Core
|
.idea/modules.xml
|
||||||
.project
|
.idea/jarRepositories.xml
|
||||||
# JDT-specific (Eclipse Java Development Tools)
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
.classpath
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding">
|
||||||
|
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
14
.idea/misc.xml
generated
Normal file
14
.idea/misc.xml
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="MavenProjectsManager">
|
||||||
|
<option name="originalFiles">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/pom.xml" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
124
.idea/uiDesigner.xml
generated
Normal file
124
.idea/uiDesigner.xml
generated
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Palette2">
|
||||||
|
<group name="Swing">
|
||||||
|
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Button" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="RadioButton" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="CheckBox" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Label" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||||
|
<preferred-size width="-1" height="20" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
</group>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
30
pom.xml
Normal file
30
pom.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.imyeyu.inject</groupId>
|
||||||
|
<artifactId>timi-inject</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.test.skip>true</maven.test.skip>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.imyeyu.io</groupId>
|
||||||
|
<artifactId>timi-io</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.5.13</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
62
src/main/java/com/imyeyu/inject/InjectApp.java
Normal file
62
src/main/java/com/imyeyu/inject/InjectApp.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package com.imyeyu.inject;
|
||||||
|
|
||||||
|
import com.imyeyu.java.bean.CallbackArg;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2024-10-10 15:20
|
||||||
|
*/
|
||||||
|
public final class InjectApp {
|
||||||
|
|
||||||
|
Object obj;
|
||||||
|
|
||||||
|
Class<?> clazz;
|
||||||
|
|
||||||
|
boolean enableBanner = true;
|
||||||
|
|
||||||
|
/** 全局注入后监听,包括静态注入 */
|
||||||
|
final List<CallbackArg<TimiInject>> afterInjectCallbackList = new ArrayList<>();
|
||||||
|
|
||||||
|
public InjectApp(Object obj) {
|
||||||
|
this.obj = obj;
|
||||||
|
this.clazz = obj.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InjectApp(Class<?> clazz) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InjectApp disableBanner() {
|
||||||
|
enableBanner = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加全局注入后监听
|
||||||
|
*
|
||||||
|
* @param listener 监听器
|
||||||
|
*/
|
||||||
|
public synchronized void addAfterInjectListener(CallbackArg<TimiInject> listener) {
|
||||||
|
afterInjectCallbackList.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除全局注入后监听
|
||||||
|
*
|
||||||
|
* @param listener 监听器
|
||||||
|
*/
|
||||||
|
public synchronized void removeAfterInjectListener(CallbackArg<TimiInject> listener) {
|
||||||
|
afterInjectCallbackList.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableBanner() {
|
||||||
|
return enableBanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableBanner(boolean enableBanner) {
|
||||||
|
this.enableBanner = enableBanner;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/main/java/com/imyeyu/inject/InjectFactory.java
Normal file
50
src/main/java/com/imyeyu/inject/InjectFactory.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package com.imyeyu.inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注入工厂,顶层接口
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:18
|
||||||
|
*/
|
||||||
|
interface InjectFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 ID 获取反转对象
|
||||||
|
*
|
||||||
|
* @param id ID
|
||||||
|
* @return 反转对象
|
||||||
|
*/
|
||||||
|
<T> T di(String id, Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型获取反转对象
|
||||||
|
*
|
||||||
|
* @param classType 类型
|
||||||
|
* @return 反转对象
|
||||||
|
* @param <T> 对象类型
|
||||||
|
*/
|
||||||
|
<T> T di(Class<T> classType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制控制反转并重新注入
|
||||||
|
*
|
||||||
|
* @param object 反转对象
|
||||||
|
*/
|
||||||
|
void ioc(Object object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制控制反转并重新注入
|
||||||
|
*
|
||||||
|
* @param clazz 反转类型
|
||||||
|
* @param object 反转对象
|
||||||
|
*/
|
||||||
|
void ioc(Class<?> clazz, Object object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制控制反转并重新注入
|
||||||
|
*
|
||||||
|
* @param id 对象 ID
|
||||||
|
* @param object 反转对象
|
||||||
|
*/
|
||||||
|
void ioc(String id, Object object);
|
||||||
|
}
|
||||||
765
src/main/java/com/imyeyu/inject/TimiInject.java
Normal file
765
src/main/java/com/imyeyu/inject/TimiInject.java
Normal file
@ -0,0 +1,765 @@
|
|||||||
|
package com.imyeyu.inject;
|
||||||
|
|
||||||
|
import com.imyeyu.inject.annotation.Bean;
|
||||||
|
import com.imyeyu.inject.annotation.Component;
|
||||||
|
import com.imyeyu.inject.annotation.Controller;
|
||||||
|
import com.imyeyu.inject.annotation.IOCAsync;
|
||||||
|
import com.imyeyu.inject.annotation.IOCPriority;
|
||||||
|
import com.imyeyu.inject.annotation.IOCReturn;
|
||||||
|
import com.imyeyu.inject.annotation.Inject;
|
||||||
|
import com.imyeyu.inject.annotation.InvokeForInjected;
|
||||||
|
import com.imyeyu.inject.annotation.Resources;
|
||||||
|
import com.imyeyu.inject.annotation.Service;
|
||||||
|
import com.imyeyu.inject.annotation.StaticInject;
|
||||||
|
import com.imyeyu.inject.annotation.SuperIOC;
|
||||||
|
import com.imyeyu.inject.annotation.SuperInject;
|
||||||
|
import com.imyeyu.inject.annotation.TimiInjectApplication;
|
||||||
|
import com.imyeyu.inject.annotation.Util;
|
||||||
|
import com.imyeyu.io.IO;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.CallbackArg;
|
||||||
|
import com.imyeyu.utils.Time;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timi 控制反转框架
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:14
|
||||||
|
*/
|
||||||
|
public class TimiInject implements InjectFactory {
|
||||||
|
|
||||||
|
/** 日志 */
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(TimiInject.class);
|
||||||
|
|
||||||
|
/** 类路径 */
|
||||||
|
private final List<String> paths;
|
||||||
|
|
||||||
|
/** 控制反转对象 */
|
||||||
|
private final Map<String, Object> objects;
|
||||||
|
|
||||||
|
/** 依赖注入字段集 */
|
||||||
|
private final List<Field> fields;
|
||||||
|
|
||||||
|
// 注入后调度 Map<对象, Map<方法, 调度顺序>>
|
||||||
|
private final Map<Object, Map<Method, Integer>> invokeForInjected;
|
||||||
|
|
||||||
|
/** 控制反转监听 */
|
||||||
|
private final Map<Class<?>, List<CallbackArg<Object>>> iocListeners;
|
||||||
|
|
||||||
|
/** 静态注入类列表 */
|
||||||
|
private final List<Class<?>> staticInject;
|
||||||
|
|
||||||
|
/** 控制反转类对象 */
|
||||||
|
private final List<IOCClass> classes;
|
||||||
|
|
||||||
|
// 异步控制反转参数
|
||||||
|
private int iocAsyncRunning = 0;
|
||||||
|
private boolean hasAsyncIOC = false;
|
||||||
|
private final Object iocAsyncLock = new Object();
|
||||||
|
|
||||||
|
private TimiInject(InjectApp app) {
|
||||||
|
if (TimiJava.isEmpty(app)) {
|
||||||
|
throw new NullPointerException("empty inject app");
|
||||||
|
}
|
||||||
|
// 初始化
|
||||||
|
long initAt = Time.now();
|
||||||
|
// Logo
|
||||||
|
if (app.enableBanner) {
|
||||||
|
if (IO.resourceExist(getClass(), "banner.txt")) {
|
||||||
|
log.info(IO.resourceToString(getClass(), "banner.txt"));
|
||||||
|
} else {
|
||||||
|
log.info(IO.resourceToString(getClass(), "defBanner.txt"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("Starting TimiInject {} ..", app.clazz);
|
||||||
|
List<String> scanPathList = new ArrayList<>();
|
||||||
|
objects = new HashMap<>();
|
||||||
|
iocListeners = new HashMap<>();
|
||||||
|
paths = new ArrayList<>();
|
||||||
|
fields = new ArrayList<>();
|
||||||
|
invokeForInjected = new LinkedHashMap<>();
|
||||||
|
staticInject = new ArrayList<>();
|
||||||
|
classes = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
// 扫描
|
||||||
|
long scanAt = Time.now();
|
||||||
|
{
|
||||||
|
// 扫描包
|
||||||
|
log.info("Scanning..");
|
||||||
|
TimiInjectApplication appAnnotation = app.clazz.getAnnotation(TimiInjectApplication.class);
|
||||||
|
if (appAnnotation == null) {
|
||||||
|
throw new NullPointerException("TimiInjectApplication can not be null, used annotation for scanner class");
|
||||||
|
}
|
||||||
|
if (TimiJava.isEmpty(appAnnotation.value())) {
|
||||||
|
scanPathList.add(app.clazz.getPackageName());
|
||||||
|
} else {
|
||||||
|
scanPathList.addAll(List.of(appAnnotation.value()));
|
||||||
|
}
|
||||||
|
// 扫描类
|
||||||
|
URI baseURI = app.clazz.getProtectionDomain().getCodeSource().getLocation().toURI();
|
||||||
|
// baseURI: 可执行 jar 或编译 classes 路径
|
||||||
|
for (int j = 0; j < scanPathList.size(); j++) {
|
||||||
|
scan(new File(baseURI).getPath(), scanPathList.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 控制反转
|
||||||
|
log.info("Running IOC..");
|
||||||
|
long iocAt = Time.now();
|
||||||
|
{
|
||||||
|
// Application IOC
|
||||||
|
if (app.obj != null) {
|
||||||
|
objects.put(app.clazz.getName(), app.obj);
|
||||||
|
// 控制反转方法返回
|
||||||
|
objects.putAll(iocReturn(app.clazz, app.obj));
|
||||||
|
// 收集此对象需要注入后调度的方法
|
||||||
|
invokeForInjected.put(app.obj, invokeForInjected(app.clazz));
|
||||||
|
}
|
||||||
|
// 自 IOC
|
||||||
|
objects.put(getClass().getName(), this);
|
||||||
|
// 其他注解 IOC
|
||||||
|
for (int j = 0; j < paths.size(); j++) {
|
||||||
|
generateIOCClass(Class.forName(paths.get(j)));
|
||||||
|
}
|
||||||
|
classes.sort(Comparator.comparingInt(o -> o.level));
|
||||||
|
for (int j = 0; j < classes.size(); j++) {
|
||||||
|
final IOCClass iocClass = classes.get(j);
|
||||||
|
try {
|
||||||
|
// 控制反转
|
||||||
|
if (iocClass.clazz.isAnnotationPresent(IOCAsync.class)) {
|
||||||
|
// 异步实例化
|
||||||
|
iocAsyncRunning++;
|
||||||
|
hasAsyncIOC = true;
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
newInstance(iocClass);
|
||||||
|
synchronized (iocAsyncLock) {
|
||||||
|
iocAsyncRunning--;
|
||||||
|
if (iocAsyncRunning < 1) {
|
||||||
|
iocAsyncLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
synchronized (iocAsyncLock) {
|
||||||
|
iocAsyncLock.notifyAll();
|
||||||
|
}
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
} else {
|
||||||
|
// 同步实例化
|
||||||
|
newInstance(iocClass);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("IOC fail id: %s, class: %s".formatted(iocClass.id, iocClass.clazz), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasAsyncIOC && iocAsyncRunning != 0) {
|
||||||
|
// 存在异步控制反转,且至少有一个类正在进行
|
||||||
|
synchronized (iocAsyncLock) {
|
||||||
|
iocAsyncLock.wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 依赖注入
|
||||||
|
log.info("Running inject..");
|
||||||
|
long injectAt = Time.now();
|
||||||
|
{
|
||||||
|
Collection<Object> objects = this.objects.values();
|
||||||
|
for (Object object : objects) {
|
||||||
|
inject(object, object.getClass());
|
||||||
|
}
|
||||||
|
// 静态注入
|
||||||
|
for (int j = 0; j < staticInject.size(); j++) {
|
||||||
|
inject(null, staticInject.get(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完成注入
|
||||||
|
for (int j = 0; j < app.afterInjectCallbackList.size(); j++) {
|
||||||
|
app.afterInjectCallbackList.get(j).handler(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("Invoking injected callback..");
|
||||||
|
// 注入调度
|
||||||
|
long invokeForInjectedAt = Time.now();
|
||||||
|
{
|
||||||
|
for (Map.Entry<Object, Map<Method, Integer>> item : invokeForInjected.entrySet()) {
|
||||||
|
for (Method method : item.getValue().keySet()) {
|
||||||
|
try {
|
||||||
|
long start = -1;
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
start = Time.now();
|
||||||
|
}
|
||||||
|
method.invoke(item.getKey());
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("invoke injected event {} ms for {}#{}", "%4s".formatted(Time.now() - start), item.getKey().getClass().getName(), method.getName());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("invoke method fail: " + item.getKey().getClass().getName() + "#" + method.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 静态
|
||||||
|
for (int j = 0; j < staticInject.size(); j++) {
|
||||||
|
Method[] methods = staticInject.get(j).getDeclaredMethods();
|
||||||
|
for (int k = 0; k < methods.length; k++) {
|
||||||
|
if (Modifier.isStatic(methods[k].getModifiers())) {
|
||||||
|
methods[k].setAccessible(true);
|
||||||
|
if (methods[k].getDeclaredAnnotation(InvokeForInjected.class) != null) {
|
||||||
|
try {
|
||||||
|
methods[k].invoke(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("invoke method fail: " + methods[k].getDeclaringClass().getName() + "#" + methods[k].getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long now = Time.now();
|
||||||
|
log.info("Completed!");
|
||||||
|
log.info("IOC objects: " + objects.size());
|
||||||
|
log.info("Inject fields: " + fields.size());
|
||||||
|
log.info("Build Time: ");
|
||||||
|
log.info("{} ms for Initialization", "%8s".formatted(scanAt - initAt));
|
||||||
|
log.info("{} ms for Scan Classes", "%8s".formatted(iocAt - scanAt));
|
||||||
|
log.info("{} ms for IOC", "%8s".formatted(injectAt - iocAt));
|
||||||
|
log.info("{} ms for Inject", "%8s".formatted(invokeForInjectedAt - injectAt));
|
||||||
|
log.info("{} ms for Invoke Callback", "%8s".formatted(now - invokeForInjectedAt));
|
||||||
|
log.info("{} ms for Total", "%8s".formatted(now - initAt));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("TimiInject run error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描包
|
||||||
|
*
|
||||||
|
* @param basePath 基本文件位置,可执行 jar 或编译 classes 路径。路径为系统分隔符
|
||||||
|
* @param scanPath 扫描位置,源码包路径,分隔符为 '.'
|
||||||
|
*/
|
||||||
|
private void scan(String basePath, String scanPath) throws IOException {
|
||||||
|
if (basePath.endsWith(".jar")) {
|
||||||
|
// 扫描 jar class
|
||||||
|
JarFile jarFile = new JarFile(basePath);
|
||||||
|
Enumeration<JarEntry> entries = jarFile.entries();
|
||||||
|
scanPath = scanPath.replace('.', '/'); // jar 内路径始终为 '/' 分隔符
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
String name = entries.nextElement().getName();
|
||||||
|
if (name.startsWith(scanPath) && name.endsWith(".class") && !name.contains("$")) {
|
||||||
|
paths.add(name.substring(0, name.length() - 6).replace('/', '.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jarFile.close();
|
||||||
|
} else {
|
||||||
|
// 扫描本地文件 class
|
||||||
|
scanPath = scanPath.replace('.', File.separatorChar);
|
||||||
|
scanFile(new File(basePath + File.separator + scanPath), basePath.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描本地 class 文件
|
||||||
|
*
|
||||||
|
* @param directory 文件夹
|
||||||
|
* @param clip 剪切位置
|
||||||
|
*/
|
||||||
|
private void scanFile(File directory, int clip) {
|
||||||
|
if (directory.isDirectory()) {
|
||||||
|
File[] files = directory.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
if (files[i].isFile()) {
|
||||||
|
String path = files[i].getPath();
|
||||||
|
if (path.endsWith(".class") && !path.contains("$")) {
|
||||||
|
paths.add(path.substring(clip + 1, path.length() - 6).replace(File.separatorChar, '.'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scanFile(files[i], clip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成类的控制反转封装,如果此类没有标记控制反转则忽略
|
||||||
|
*
|
||||||
|
* @param clazz 类对象
|
||||||
|
*/
|
||||||
|
private void generateIOCClass(Class<?> clazz) {
|
||||||
|
boolean isBean = clazz.isAnnotationPresent(Bean.class);
|
||||||
|
boolean isComponent = clazz.isAnnotationPresent(Component.class);
|
||||||
|
boolean isService = clazz.isAnnotationPresent(Service.class);
|
||||||
|
boolean isController = clazz.isAnnotationPresent(Controller.class);
|
||||||
|
boolean isResources = clazz.isAnnotationPresent(Resources.class);
|
||||||
|
boolean isUtil = clazz.isAnnotationPresent(Util.class);
|
||||||
|
// 注入
|
||||||
|
boolean isInject = clazz.isAnnotationPresent(Inject.class);
|
||||||
|
boolean isStaticInject = clazz.isAnnotationPresent(StaticInject.class);
|
||||||
|
|
||||||
|
// 获取反转对象 ID
|
||||||
|
if (!(isBean || isComponent || isService || isController || isResources || isUtil || isInject)) {
|
||||||
|
// 非控制反转相关类
|
||||||
|
if (isStaticInject) {
|
||||||
|
// 静态注入
|
||||||
|
staticInject.add(clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = null;
|
||||||
|
if (isBean) {
|
||||||
|
id = clazz.getAnnotation(Bean.class).value();
|
||||||
|
}
|
||||||
|
if (isComponent) {
|
||||||
|
id = clazz.getAnnotation(Component.class).value();
|
||||||
|
}
|
||||||
|
if (isService) {
|
||||||
|
id = clazz.getAnnotation(Service.class).value();
|
||||||
|
}
|
||||||
|
if (isController) {
|
||||||
|
id = clazz.getAnnotation(Controller.class).value();
|
||||||
|
}
|
||||||
|
if (isResources) {
|
||||||
|
id = clazz.getAnnotation(Resources.class).value();
|
||||||
|
}
|
||||||
|
if (isUtil) {
|
||||||
|
id = clazz.getAnnotation(Util.class).value();
|
||||||
|
}
|
||||||
|
if (isInject) {
|
||||||
|
id = clazz.getAnnotation(Inject.class).value();
|
||||||
|
}
|
||||||
|
if (id != null) {
|
||||||
|
IOCClass iocClass = new IOCClass(id, clazz.getName(), clazz.isAnnotationPresent(IOCAsync.class), clazz);
|
||||||
|
if (clazz.isAnnotationPresent(IOCPriority.class)) {
|
||||||
|
// IOCPriority 注解类和异步控制反转优先实例化
|
||||||
|
iocClass.level = clazz.getAnnotation(IOCPriority.class).value();
|
||||||
|
}
|
||||||
|
classes.add(iocClass);
|
||||||
|
// 静态子类和父级静态子类控制反转
|
||||||
|
Class<?> superClass = clazz;
|
||||||
|
do {
|
||||||
|
Class<?>[] declaredClasses = superClass.getDeclaredClasses();
|
||||||
|
for (int i = 0; i < declaredClasses.length; i++) {
|
||||||
|
if (Modifier.isStatic(declaredClasses[i].getModifiers())) {
|
||||||
|
generateIOCClass(declaredClasses[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (superClass.isAnnotationPresent(SuperIOC.class) && (superClass = superClass.getSuperclass()) != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实例化控制反转对象
|
||||||
|
*
|
||||||
|
* @param iocClass 控制反转类
|
||||||
|
* @throws NoSuchMethodException 不存在构造方法异常
|
||||||
|
* @throws InvocationTargetException 调用异常
|
||||||
|
* @throws InstantiationException 实例化异常
|
||||||
|
* @throws IllegalAccessException 访问异常
|
||||||
|
*/
|
||||||
|
private void newInstance(IOCClass iocClass) throws Exception {
|
||||||
|
long start = -1;
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
start = Time.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
Constructor<?> constructor = iocClass.clazz.getDeclaredConstructor();
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
Object object = constructor.newInstance();
|
||||||
|
if (TimiJava.isEmpty(iocClass.id)) {
|
||||||
|
objects.put(iocClass.path, object);
|
||||||
|
} else {
|
||||||
|
objects.put(iocClass.id, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
if (iocClass.isAsync) {
|
||||||
|
log.debug("IOC {} ms(async) for {}: {}", "%4s".formatted(Time.now() - start), iocClass.id, iocClass.clazz.getName());
|
||||||
|
} else {
|
||||||
|
log.debug("IOC {} ms for {}: {}", "%4s".formatted(Time.now() - start), iocClass.id, iocClass.clazz.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 控制反转方法返回
|
||||||
|
objects.putAll(iocReturn(object.getClass(), object));
|
||||||
|
// 收集此对象需要注入后调度的方法
|
||||||
|
invokeForInjected.put(object, invokeForInjected(object.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转方法返回对象
|
||||||
|
*
|
||||||
|
* @param clazz 所属类
|
||||||
|
* @param object 类对象
|
||||||
|
* @return 控制反转对象
|
||||||
|
*/
|
||||||
|
private Map<String, Object> iocReturn(Class<?> clazz, Object object) {
|
||||||
|
Map<String, Object> iocObjects = new HashMap<>();
|
||||||
|
// 控制反转方法返回
|
||||||
|
Method[] methods = clazz.getDeclaredMethods();
|
||||||
|
for (int i = 0; i < methods.length; i++) {
|
||||||
|
try {
|
||||||
|
methods[i].setAccessible(true);
|
||||||
|
IOCReturn iocReturn = methods[i].getAnnotation(IOCReturn.class);
|
||||||
|
if (iocReturn != null) {
|
||||||
|
if (methods[i].isAnnotationPresent(IOCAsync.class)) {
|
||||||
|
iocAsyncRunning++;
|
||||||
|
hasAsyncIOC = true;
|
||||||
|
|
||||||
|
final int j = i;
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
long start = -1;
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
start = Time.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object returnObject = methods[j].invoke(object);
|
||||||
|
if (returnObject == null) {
|
||||||
|
throw new NullPointerException("return IOC object can not be null: " + clazz.getSimpleName() + "#" + methods[j].getName());
|
||||||
|
}
|
||||||
|
String id = iocReturn.value();
|
||||||
|
if (TimiJava.isEmpty(id)) {
|
||||||
|
id = returnObject.getClass().getName() + "#" + methods[j].getName();
|
||||||
|
}
|
||||||
|
objects.put(id, returnObject);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("IOC {} ms(async) for {}: {}", "%4s".formatted(Time.now() - start), id, returnObject.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (iocAsyncLock) {
|
||||||
|
iocAsyncRunning--;
|
||||||
|
if (iocAsyncRunning < 1) {
|
||||||
|
iocAsyncLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
synchronized (iocAsyncLock) {
|
||||||
|
iocAsyncLock.notifyAll();
|
||||||
|
}
|
||||||
|
log.error("IOC fail class: %s#%s".formatted(clazz.getName(), methods[j].getName()), e);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
} else {
|
||||||
|
long start = -1;
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
start = Time.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object returnObject = methods[i].invoke(object);
|
||||||
|
if (returnObject == null) {
|
||||||
|
throw new NullPointerException("return IOC object can not be null: " + clazz.getSimpleName() + "#" + methods[i].getName());
|
||||||
|
}
|
||||||
|
String id = iocReturn.value();
|
||||||
|
if (TimiJava.isEmpty(id)) {
|
||||||
|
id = returnObject.getClass().getName() + "#" + methods[i].getName();
|
||||||
|
}
|
||||||
|
iocObjects.put(id, returnObject);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("IOC {} ms for {}: {}", "%4s".formatted(Time.now() - start), id, returnObject.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
|
log.error("IOC fail class: %s#%s".formatted(clazz.getName(), methods[i].getName()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iocObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向变量注入对象
|
||||||
|
*
|
||||||
|
* @param object 控制反转对象
|
||||||
|
* @param clazz 该变量类型(存在父级注入时递归调用)
|
||||||
|
*/
|
||||||
|
private void inject(Object object, Class<?> clazz) throws IllegalAccessException {
|
||||||
|
if (clazz.isAnnotationPresent(SuperInject.class)) {
|
||||||
|
// 父级注入
|
||||||
|
inject(object, clazz.getSuperclass());
|
||||||
|
}
|
||||||
|
injectFields(object, clazz.getDeclaredFields());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向变量字段注入对象
|
||||||
|
*
|
||||||
|
* @param object 目标
|
||||||
|
* @param fields 字段
|
||||||
|
*/
|
||||||
|
private void injectFields(Object object, Field... fields) throws IllegalAccessException {
|
||||||
|
for (int i = 0; i < fields.length; i++) {
|
||||||
|
if (object == null) {
|
||||||
|
if (!Modifier.isStatic(fields[i].getModifiers())) {
|
||||||
|
// 静态注入,忽略非静态属性
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Inject inject = fields[i].getAnnotation(Inject.class);
|
||||||
|
if (inject != null) {
|
||||||
|
fields[i].setAccessible(true);
|
||||||
|
if (fields[i].getType().equals(TimiInject.class)) {
|
||||||
|
// 注入注射器
|
||||||
|
fields[i].set(object, this);
|
||||||
|
} else {
|
||||||
|
String value = inject.value();
|
||||||
|
// 执行注入
|
||||||
|
if (TimiJava.isEmpty(value)) {
|
||||||
|
String id = fields[i].getType().getName() + "#" + fields[i].getName();
|
||||||
|
|
||||||
|
log.debug("Injecting {}", id);
|
||||||
|
Object diObject = di(id, Object.class);
|
||||||
|
try {
|
||||||
|
if (diObject == null) {
|
||||||
|
fields[i].set(object, di(fields[i].getType()));
|
||||||
|
} else {
|
||||||
|
fields[i].set(object, diObject);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (object == null) {
|
||||||
|
throw new RuntimeException("inject field fail: null#" + fields[i].getName(), e);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("inject field fail: " + object.getClass().getName() + "#" + fields[i].getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fields[i].set(object, objects.get(value));
|
||||||
|
}
|
||||||
|
// 添加到集合
|
||||||
|
this.fields.add(fields[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收集此对象需要注入后调度的方法
|
||||||
|
*
|
||||||
|
* @param clazz 对象类
|
||||||
|
*/
|
||||||
|
private Map<Method, Integer> invokeForInjected(Class<?> clazz) {
|
||||||
|
Map<Method, Integer> map = new HashMap<>();
|
||||||
|
if (clazz.isAnnotationPresent(SuperInject.class)) {
|
||||||
|
// 父级调度
|
||||||
|
map.putAll(invokeForInjected(clazz.getSuperclass()));
|
||||||
|
}
|
||||||
|
Method[] methods = clazz.getDeclaredMethods();
|
||||||
|
for (int i = 0; i < methods.length; i++) {
|
||||||
|
methods[i].setAccessible(true);
|
||||||
|
InvokeForInjected invokeForInjected = methods[i].getAnnotation(InvokeForInjected.class);
|
||||||
|
if (invokeForInjected != null) {
|
||||||
|
map.put(methods[i], invokeForInjected.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
List<Map.Entry<Method, Integer>> list = new ArrayList<>(map.entrySet());
|
||||||
|
list.sort(Comparator.comparingDouble(o -> o.getValue().doubleValue()));
|
||||||
|
|
||||||
|
LinkedHashMap<Method, Integer> result = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<Method, Integer> entry : list) {
|
||||||
|
result.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行 TimiInject 注入框架,此方法应运行且只运行一次
|
||||||
|
*
|
||||||
|
* @param clazz TimiInjectApplication 注解的类
|
||||||
|
*/
|
||||||
|
public static synchronized TimiInject run(Class<?> clazz) {
|
||||||
|
return run(new InjectApp(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行 TimiInject 注入框架,此方法应运行且只运行一次
|
||||||
|
*
|
||||||
|
* @param obj TimiInjectApplication 注解的对象
|
||||||
|
*/
|
||||||
|
public static synchronized TimiInject run(Object obj) {
|
||||||
|
return run(new InjectApp(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行 TimiInject 注入框架,此方法应运行且只运行一次
|
||||||
|
*
|
||||||
|
* @param app 控制反转应用
|
||||||
|
*/
|
||||||
|
public static synchronized TimiInject run(InjectApp app) {
|
||||||
|
return new TimiInject(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 ID 获取依赖注入对象
|
||||||
|
*
|
||||||
|
* @param id ID
|
||||||
|
* @return 控制反转的对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T di(String id, Class<T> clazz) {
|
||||||
|
return clazz.cast(objects.get(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型获取依赖注入对象
|
||||||
|
*
|
||||||
|
* @param classType 类型
|
||||||
|
* @param <T> 控制反转类型
|
||||||
|
* @return 控制反转对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T di(Class<T> classType) {
|
||||||
|
for (Object next : objects.values()) {
|
||||||
|
if (next.getClass().getName().equals(classType.getName()) || classType.isAssignableFrom(next.getClass())) {
|
||||||
|
return classType.cast(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ioc(Object object) {
|
||||||
|
ioc(object.getClass(), object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ioc(Class<?> clazz, Object object) {
|
||||||
|
ioc(clazz.getName(), object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ioc(String id, Object object) {
|
||||||
|
try {
|
||||||
|
log.info("Call IOC: " + id);
|
||||||
|
// ---------- 控制反转 ----------
|
||||||
|
long iocAt = Time.now();
|
||||||
|
// 本类对象
|
||||||
|
objects.put(id, object);
|
||||||
|
// 方法返回对象
|
||||||
|
Map<String, Object> iocReturnObjects = iocReturn(object.getClass(), object);
|
||||||
|
objects.putAll(iocReturnObjects);
|
||||||
|
|
||||||
|
// ---------- 注入 ----------
|
||||||
|
long injectAt = Time.now();
|
||||||
|
// 本类对象字段
|
||||||
|
inject(object, object.getClass());
|
||||||
|
// 其他类的本类对象注入
|
||||||
|
for (int i = 0; i < fields.size(); i++) {
|
||||||
|
if (fields.get(i).getType().equals(object.getClass())) {
|
||||||
|
fields.get(i).set(di(fields.get(i).getDeclaringClass()), object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 方法返回对象注入
|
||||||
|
for (Map.Entry<String, Object> iocObject : iocReturnObjects.entrySet()) {
|
||||||
|
for (int i = 0; i < fields.size(); i++) {
|
||||||
|
if (fields.get(i).getType().equals(iocObject.getValue().getClass())) {
|
||||||
|
fields.get(i).set(di(fields.get(i).getDeclaringClass()), iocObject.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long afterInjectingAt = Time.now();
|
||||||
|
// 一般注入后调度
|
||||||
|
Map<Method, Integer> methods = invokeForInjected(object.getClass());
|
||||||
|
for (Map.Entry<Method, Integer> method : methods.entrySet()) {
|
||||||
|
method.getKey().invoke(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
long callIOCListenersAt = Time.now();
|
||||||
|
// 控制反转监听
|
||||||
|
if (iocListeners.get(object.getClass()) != null) {
|
||||||
|
List<CallbackArg<Object>> listeners = iocListeners.get(object.getClass());
|
||||||
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
|
listeners.get(i).handler(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long now = Time.now();
|
||||||
|
log.info("Completed for {} IOC object in {} ms", (iocReturnObjects.size() + 1), now - iocAt);
|
||||||
|
|
||||||
|
log.debug("Build Time Detail: ");
|
||||||
|
log.debug("{} ms for IOC", "%8s".formatted(injectAt - iocAt));
|
||||||
|
log.debug("{} ms for Inject", "%8s".formatted(afterInjectingAt - injectAt));
|
||||||
|
log.debug("{} ms for Injected Event", "%8s".formatted(callIOCListenersAt - afterInjectingAt));
|
||||||
|
log.debug("{} ms for IOC Listener Event", "%8s".formatted(now - callIOCListenersAt));
|
||||||
|
log.debug("{} ms for Total", "%8s".formatted(now - iocAt));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("call ioc fail: " + id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加控制反转监听,这通常是为强制控制反转的类监听,因为第一轮控制反转是监听不到的
|
||||||
|
*
|
||||||
|
* @param clazz 控制反转类
|
||||||
|
* @param listener 监听器
|
||||||
|
*/
|
||||||
|
public synchronized void addIOCListener(Class<?> clazz, CallbackArg<Object> listener) {
|
||||||
|
iocListeners.computeIfAbsent(clazz, k -> new ArrayList<>()).add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除控制反转监听
|
||||||
|
*
|
||||||
|
* @param clazz 控制反转类
|
||||||
|
* @param listener 监听器
|
||||||
|
*/
|
||||||
|
public synchronized void removeIOCListener(Class<?> clazz, CallbackArg<Object> listener) {
|
||||||
|
iocListeners.computeIfAbsent(clazz, k -> new ArrayList<>()).remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转类
|
||||||
|
*
|
||||||
|
* <p>夜雨 创建于 2022-10-11 09:42
|
||||||
|
*/
|
||||||
|
private static class IOCClass {
|
||||||
|
|
||||||
|
/** id */
|
||||||
|
String id;
|
||||||
|
|
||||||
|
/** 类路径 */
|
||||||
|
String path;
|
||||||
|
|
||||||
|
/** true 为异步实例化 */
|
||||||
|
boolean isAsync;
|
||||||
|
|
||||||
|
/** 类对象 */
|
||||||
|
Class<?> clazz;
|
||||||
|
|
||||||
|
/** 优先级 */
|
||||||
|
int level;
|
||||||
|
|
||||||
|
public IOCClass(String id, String path, boolean isAsync, Class<?> clazz) {
|
||||||
|
this.id = id;
|
||||||
|
this.path = path;
|
||||||
|
this.isAsync = isAsync;
|
||||||
|
this.clazz = clazz;
|
||||||
|
this.level = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/main/java/com/imyeyu/inject/annotation/Bean.java
Normal file
26
src/main/java/com/imyeyu/inject/annotation/Bean.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转(通用对象),注解在类上后该类将被 TimiInject 实例化并控制反转,后续执行注入
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2024-07-19 15:48
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Bean {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对象名称,非空时注入需要明确执行
|
||||||
|
*
|
||||||
|
* @return 对象名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
26
src/main/java/com/imyeyu/inject/annotation/Component.java
Normal file
26
src/main/java/com/imyeyu/inject/annotation/Component.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转(组件),注解在类上后该类将被 TimiInject 实例化并控制反转,后续执行注入
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:16
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Component {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件名称,非空时注入需要明确执行
|
||||||
|
*
|
||||||
|
* @return 组件名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
26
src/main/java/com/imyeyu/inject/annotation/Controller.java
Normal file
26
src/main/java/com/imyeyu/inject/annotation/Controller.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转(控制器),注解在类上后该类将被 TimiInject 实例化并控制反转,后续执行注入
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:16
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Controller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制器名称,非空时注入需要明确执行
|
||||||
|
*
|
||||||
|
* @return 控制器名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
22
src/main/java/com/imyeyu/inject/annotation/IOCAsync.java
Normal file
22
src/main/java/com/imyeyu/inject/annotation/IOCAsync.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>异步控制反转,控制反转的类或 {@link IOCReturn} 方法使用此注解将会在异步线程中实例化或调用。
|
||||||
|
* 此注解不影响注入流程。
|
||||||
|
* <p>此注解对实例化比较耗时的动作有明显的速度提升,有 {@link IOCPriority} 的效果,对实例化耗时较短的动作使用将会适得其反。
|
||||||
|
* <p><u>注意:JavaFX 组件不可用,因为它只有一个 UI 线程</u>
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-10-10 17:05
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface IOCAsync {
|
||||||
|
}
|
||||||
27
src/main/java/com/imyeyu/inject/annotation/IOCPriority.java
Normal file
27
src/main/java/com/imyeyu/inject/annotation/IOCPriority.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转类使用此注解时将会优先执行实例化,对不存在异步控制反转的类使用不会提升效率。
|
||||||
|
* <p>使用此注解后,{@link InvokeForInjected} 的方法也会优先于其他类触发
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-10-10 23:17
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface IOCPriority {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级,默认所有使用此注解的类都会往前挤,除非使用指定等级,数值小的优先执行
|
||||||
|
*
|
||||||
|
* @return 优先等级,默认 {@link Integer#MAX_VALUE} / 2,非此注解的类的优先级为 {@link Integer#MAX_VALUE}
|
||||||
|
*/
|
||||||
|
int value() default Integer.MAX_VALUE / 2;
|
||||||
|
}
|
||||||
30
src/main/java/com/imyeyu/inject/annotation/IOCReturn.java
Normal file
30
src/main/java/com/imyeyu/inject/annotation/IOCReturn.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转(方法返回对象),注解在方法上,该方法所在类也必须控制反转到 TimiInject 中,经过此注解的方法返回值也会控制反转到 TimiInject 中并后续执行注入
|
||||||
|
*
|
||||||
|
* <p><b><u>注意:注解参数为空时 {@link Inject} 注入对象的变量名需要和此方法名一致</u></b></p>
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:16
|
||||||
|
*/
|
||||||
|
@Target({ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface IOCReturn {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对象名称,非空时注入需要明确指定
|
||||||
|
*
|
||||||
|
* <p><b><u>为空时注入对象的变量名需要和此方法名一致</u></b></p>
|
||||||
|
*
|
||||||
|
* @return 对象名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
30
src/main/java/com/imyeyu/inject/annotation/Inject.java
Normal file
30
src/main/java/com/imyeyu/inject/annotation/Inject.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注入,使用在类变量上,该变量的类需要在 TimiInject 控制反转中才能执行对象注入
|
||||||
|
*
|
||||||
|
* <p>注意
|
||||||
|
* <ul>
|
||||||
|
* <li><u>如果该类使用 {@link StaticInject} 静态注入,此变量必须为静态变量</u></li>
|
||||||
|
* <li><u>如果是 {@link IOCReturn} 控制反转的对象,并且控制反转时没有指定名称,此变量名称需要和控制反转方法名一致</u></li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:15
|
||||||
|
*/
|
||||||
|
@Target({ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Inject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注入名称,控制反转明确指定名称时此属性也需要明确指定
|
||||||
|
*
|
||||||
|
* @return 注入名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此注解使用在方法上,TimiInject 完成注入后自动执行,对 {@link StaticInject} 和 {@link SuperInject} 有效,方法访问权限无限制。
|
||||||
|
* <p>注意:{@link StaticInject} 注解类的方法使用此注解时,该方法也必须是静态方法
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* @Component
|
||||||
|
* public class Demo {
|
||||||
|
*
|
||||||
|
* @InvokeForInjected
|
||||||
|
* public void hello() {
|
||||||
|
* System.out.println("hello");
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @InvokeForInjected
|
||||||
|
* public void timiInject() {
|
||||||
|
* System.out.println("timi-inject");
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-09-23 22:25
|
||||||
|
*/
|
||||||
|
@Target({ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface InvokeForInjected {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行顺序,默认 0,数值小的先执行
|
||||||
|
*
|
||||||
|
* @return 执行顺序
|
||||||
|
*/
|
||||||
|
int value() default 0;
|
||||||
|
}
|
||||||
26
src/main/java/com/imyeyu/inject/annotation/Resources.java
Normal file
26
src/main/java/com/imyeyu/inject/annotation/Resources.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转(资源),注解在类上后该类将被 TimiInject 实例化并控制反转托管,后续执行注入
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:16
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Resources {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源名称,非空时注入需要明确执行
|
||||||
|
*
|
||||||
|
* @return 资源名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
26
src/main/java/com/imyeyu/inject/annotation/Service.java
Normal file
26
src/main/java/com/imyeyu/inject/annotation/Service.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转(服务),注解在类上后该类将被 TimiInject 实例化并控制反转托管,后续执行注入
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:16
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Service {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务名称,非空时注入需要明确执行
|
||||||
|
*
|
||||||
|
* @return 服务名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
27
src/main/java/com/imyeyu/inject/annotation/StaticInject.java
Normal file
27
src/main/java/com/imyeyu/inject/annotation/StaticInject.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态注入,此类的<u>静态属性</u>将会在控制反转完成后进行注入,<u>此注解的类不会控制反转实例到 TimiInject 中</u>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link InvokeForInjected} 对本注解有效,但必须是静态方法</li>
|
||||||
|
* </ul>
|
||||||
|
* <pre>
|
||||||
|
* @InvokeForInjected
|
||||||
|
* public static void injected() {
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-06-24 11:29
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface StaticInject {
|
||||||
|
}
|
||||||
19
src/main/java/com/imyeyu/inject/annotation/SuperIOC.java
Normal file
19
src/main/java/com/imyeyu/inject/annotation/SuperIOC.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父级控制反转,通常用于父级存在控制反转子类时使用,父级可以继续使用此注解
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2023-02-28 11:42
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface SuperIOC {
|
||||||
|
}
|
||||||
21
src/main/java/com/imyeyu/inject/annotation/SuperInject.java
Normal file
21
src/main/java/com/imyeyu/inject/annotation/SuperInject.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父级注入,用在控制反转的类上,对控制反转的对象父级的变量也执行注入对象,父级也可以继续使用此注解
|
||||||
|
*
|
||||||
|
* <p>*对 {@link StaticInject} 无效
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:16
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface SuperInject {
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import com.imyeyu.inject.TimiInject;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TimiInject 注入程序,{@link TimiInject} 核心将基于此注解类的位置(或注解参数)进行包扫描和控制反转
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2022-03-04 23:32
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface TimiInjectApplication {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描包位置(如:com.imyeyu.inject),此包下的所有类将检测控制反转和注入,留空则使用注解的类所在包作为扫描位置。
|
||||||
|
* <p><u>TimiInject 的所有注解在此包扫描范围内有效</u></p>
|
||||||
|
*
|
||||||
|
* @return 扫描包位置
|
||||||
|
*/
|
||||||
|
String[] value() default {};
|
||||||
|
}
|
||||||
26
src/main/java/com/imyeyu/inject/annotation/Util.java
Normal file
26
src/main/java/com/imyeyu/inject/annotation/Util.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.imyeyu.inject.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制反转(工具),注解在类上后该类将被 TimiInject 实例化并控制反转,后续执行注入
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @version 2023-05-18 00:36
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Util {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具名称,非空时注入需要明确执行
|
||||||
|
*
|
||||||
|
* @return 工具名称
|
||||||
|
*/
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
/** 控制反转和注入注解 */
|
||||||
|
package com.imyeyu.inject.annotation;
|
||||||
2
src/main/java/com/imyeyu/inject/package-info.java
Normal file
2
src/main/java/com/imyeyu/inject/package-info.java
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/** 主程序 */
|
||||||
|
package com.imyeyu.inject;
|
||||||
9
src/main/resources/defBanner.txt
Normal file
9
src/main/resources/defBanner.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
_____ _ _ ___ _ _ __ _ _
|
||||||
|
|_ _(_)_ __ ___ (_) |_ _|_ __ (_) ___ ___| |_ \ \ \ \
|
||||||
|
| | | | '_ ` _ \| | | || '_ \ | |/ _ \/ __| __| \ \ \ \
|
||||||
|
| | | | | | | | | | | || | | || | __/ (__| |_ ) ) ) )
|
||||||
|
|_| |_|_| |_| |_|_| |___|_| |_|/ |\___|\___|\__| / / / /
|
||||||
|
---------------------------------|__/---------------/_/_/_/
|
||||||
|
|
||||||
|
Banner drawn by https://patorjk.com/software/taag for Ivrit
|
||||||
29
src/main/resources/logback.xml
Normal file
29
src/main/resources/logback.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<configuration>
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>[%d{HH:mm:ss.SSS}][%-5level][%-54logger{54}] %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>./logs/debug.log</file>
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>[%d{HH:mm:ss.SSS}][%-5level][%-54logger{54}] %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>./logs/debug/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
<appender-ref ref="file" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
Reference in New Issue
Block a user