Spring之手写一个依赖注入容器 1. 创建两个自定义注解 2. ApplicationContext接口与实现类 2.1 ApplicationContext 接口 2.2 实现类:DefaultListableApplicationContext 3. 定义DAO层和Service层及其实现 4. 定义异常信息类 4.1 InjectBeanException 4.2 NotExistsBean 4.3 NotSupportMoreSuperInterface 5. 测试自定义bean容器(带依赖注入) 5.1 新建测试类TestUser 5.2 输出结果
1. 创建两个自定义注解
1.1 Component注解
@Target ( value = ElementType . TYPE )
@Retention ( RetentionPolicy . RUNTIME )
public @interface Component { String value ( ) default "" ;
}
1.2 DI注解
@Target ( value = ElementType . FIELD )
@Retention ( RetentionPolicy . RUNTIME )
public @interface DI { String value ( ) default "" ; }
2. ApplicationContext接口与实现类
2.1 ApplicationContext 接口
public interface ApplicationContext { Object getBean ( String name) ; < T > T getBean ( String name, Class < T > clazz) ; boolean exists ( String name) ; boolean exists ( String name, Class < ? > clazz) ;
}
2.2 实现类:DefaultListableApplicationContext
public class DefaultListableApplicationContext implements ApplicationContext { private Map < String , Object > objectsMap = new ConcurrentHashMap < > ( 128 ) ; private Map < Class , Object > objectsTypeMap = new ConcurrentHashMap < > ( 128 ) ; private Logger log = LoggerFactory . getLogger ( DefaultListableApplicationContext . class ) ; private String basePath; public DefaultListableApplicationContext ( String basePackage) { String packagePath = basePackage. replaceAll ( "\\." , "\\\\" ) ; try { URL url = Thread . currentThread ( ) . getContextClassLoader ( ) . getResource ( packagePath) ; if ( StringUtils . hasText ( url. getPath ( ) ) ) { String filePath = URLDecoder . decode ( url. getFile ( ) , "UTF8" ) ; basePath = filePath. substring ( 0 , filePath. length ( ) - packagePath. length ( ) ) ; loadBeans ( new File ( filePath) ) ; loadDI ( ) ; } } catch ( IOException e) { throw new RuntimeException ( e) ; } } @Override @Nullable public Object getBean ( String name) { return objectsMap. get ( name) ; } @Override @Nullable public < T > T getBean ( String name, Class < T > clazz) { Object obj = objectsMap. get ( name) ; if ( obj == null ) { Object bean; if ( ( bean = objectsTypeMap. get ( clazz) ) == null ) { for ( Class < ? > interfaceClazz : clazz. getInterfaces ( ) ) { if ( ( bean = objectsTypeMap. get ( interfaceClazz) ) != null ) return ( T ) bean; getBean ( name, interfaceClazz) ; } return null ; } return ( T ) bean; } return clazz. isInstance ( obj) ? clazz. cast ( obj) : null ; } @Override public boolean exists ( String name) { return objectsMap. get ( name) == null ? false : true ; } @Override public boolean exists ( String name, Class < ? > clazz) { if ( objectsMap. get ( name) == null ) { if ( objectsTypeMap. get ( clazz) == null ) { for ( Class < ? > interfaceClazz : clazz. getInterfaces ( ) ) { if ( objectsTypeMap. get ( interfaceClazz) != null ) return true ; exists ( name, interfaceClazz) ; } return false ; } return true ; } return true ; } private void loadBeans ( File file) { if ( file. isDirectory ( ) ) { File [ ] childrenFiles = file. listFiles ( ) ; if ( childrenFiles == null || childrenFiles. length == 0 ) { return ; } for ( File childFile : childrenFiles) { if ( childFile. isDirectory ( ) ) { loadBeans ( childFile) ; } else { String pathWithClass = childFile. getAbsolutePath ( ) . substring ( basePath. length ( ) - 1 ) ; if ( pathWithClass. endsWith ( ".class" ) ) { String allName = pathWithClass. replaceAll ( "\\\\" , "." ) . replace ( ".class" , "" ) ; try { Class < ? > clazz = Class . forName ( allName) ; if ( ! clazz. isInterface ( ) ) { if ( clazz. getAnnotation ( Component . class ) != null ) { Object instance = clazz. getConstructor ( ) . newInstance ( ) ; if ( StringUtils . hasText ( clazz. getAnnotation ( Component . class ) . value ( ) ) ) { String beanName = clazz. getAnnotation ( Component . class ) . value ( ) ; objectsMap. put ( beanName, instance) ; log. warn ( ">>> objectsMap store bean(name,obj) ===> (" + beanName + "," + instance + ")" ) ; if ( clazz. getInterfaces ( ) . length == 1 ) { objectsTypeMap. put ( clazz. getInterfaces ( ) [ 0 ] , instance) ; log. warn ( ">>> objectsTypeMap store bean(class,obj) ===> (" + clazz. getInterfaces ( ) [ 0 ] . getSimpleName ( ) + "," + instance + ")" ) ; } else if ( clazz. getInterfaces ( ) . length == 0 ) { objectsTypeMap. put ( clazz, instance) ; log. warn ( ">>> objectsTypeMap store bean(class,obj) ===> (" + clazz. getInterfaces ( ) [ 0 ] . getSimpleName ( ) + "," + instance + ")" ) ; } else { throw new NotSupportMoreSuperInterface ( "Not support the bean that has more than two super interfaces." ) ; } } else if ( clazz. getInterfaces ( ) . length > 0 ) { String interfaceName = clazz. getInterfaces ( ) [ 0 ] . getSimpleName ( ) ; String beanName = lowercaseFirstLetter ( interfaceName) ; objectsMap. put ( beanName, instance) ; log. warn ( ">>> objectsMap store bean(name,obj) ===> (" + beanName + "," + instance + ")" ) ; objectsTypeMap. put ( clazz. getInterfaces ( ) [ 0 ] , instance) ; log. warn ( ">>> objectsTypeMap store bean(class,obj) ===> (" + clazz. getInterfaces ( ) [ 0 ] . getSimpleName ( ) + "," + instance + ")" ) ; } else { String beanName = lowercaseFirstLetter ( clazz. getSimpleName ( ) ) ; objectsMap. put ( beanName, instance) ; log. warn ( ">>> objectsMap store bean(name,obj) ===> (" + beanName + "," + instance + ")" ) ; objectsTypeMap. put ( clazz, instance) ; log. warn ( ">>> objectsTypeMap store bean(class,obj) ===> (" + clazz. getInterfaces ( ) [ 0 ] . getSimpleName ( ) + "," + instance + ")" ) ; } } } } catch ( Exception e) { throw new RuntimeException ( e) ; } } } } } } private void loadDI ( ) { for ( Map. Entry < String , Object > entry : objectsMap. entrySet ( ) ) { Object obj = entry. getValue ( ) ; Class < ? > clazz = obj. getClass ( ) ; Field [ ] fields = clazz. getDeclaredFields ( ) ; for ( Field field : fields) { try { field. setAccessible ( true ) ; if ( field. getAnnotation ( DI . class ) != null ) { Class < ? > [ ] interfaces = field. getType ( ) . getInterfaces ( ) ; String needWiredBeanName; Object autoWiredBean; if ( StringUtils . hasText ( needWiredBeanName = field. getAnnotation ( DI . class ) . value ( ) ) ) { autoWiredBean = objectsMap. get ( needWiredBeanName) ; if ( autoWiredBean != null ) { field. set ( obj, autoWiredBean) ; log. warn ( "<<< DI: Class " + clazz. getSimpleName ( ) + " of field named " + field. getName ( ) + " is injected with value of " + autoWiredBean + " from " + "objectsMap, by value of annotation @DI" ) ; continue ; } } needWiredBeanName = lowercaseFirstLetter ( field. getType ( ) . getSimpleName ( ) ) ; if ( ( autoWiredBean = objectsMap. get ( needWiredBeanName) ) != null || ( autoWiredBean = objectsTypeMap. get ( field. getType ( ) ) ) != null ) { field. set ( obj, autoWiredBean) ; log. warn ( "<<< DI: Class " + clazz. getSimpleName ( ) + " of field named " + field. getName ( ) + " is injected with value of " + autoWiredBean + " , by value or type of property itself " ) ; continue ; } if ( interfaces. length > 0 ) { for ( Class < ? > interfaceClazz : interfaces) { String interfaceClazzName = interfaceClazz. getSimpleName ( ) ; if ( interfaceClazz. isAssignableFrom ( field. getType ( ) ) ) { needWiredBeanName = lowercaseFirstLetter ( interfaceClazzName) ; if ( ( autoWiredBean = objectsMap. get ( needWiredBeanName) ) != null || ( autoWiredBean = objectsTypeMap. get ( interfaceClazz) ) != null ) { field. set ( obj, autoWiredBean) ; log. warn ( "<<< DI: Class " + clazz. getSimpleName ( ) + " of field named " + field. getName ( ) + " is injected with value of " + autoWiredBean + ", by value or type of super interface" ) ; } } } continue ; } throw new InjectBeanException ( "There occurs an Exception while injecting property filed [" + field. getName ( ) + "] of Class <" + clazz. getSimpleName ( ) + "> , because bean factory doesn't exist the bean named " + needWiredBeanName) ; } } catch ( IllegalAccessException e) { throw new RuntimeException ( e) ; } } } } private String lowercaseFirstLetter ( String name) { return name. substring ( 0 , 1 ) . toLowerCase ( ) + name. substring ( 1 ) ; } }
3. 定义DAO层和Service层及其实现
public interface UserDao { void addUser ( User user) ;
}
@Component ( "userDao" )
public class UserDaoImpl implements UserDao { @Override public void addUser ( User user) { System . out. println ( ) ; System . out. println ( "------------------>>>执行UserDaoImpl中的addUser方法开始<<<<------------------" ) ; System . out. println ( "\t\t\t\t\t\t名字\t\t\t\t年龄" ) ; System . out. println ( "\t\t\t\t\t\t" + user. getName ( ) + "\t\t\t\t" + user. getAge ( ) ) ; System . out. println ( "------------------>>>执行UserDaoImpl中的addUser方法完毕<<<<------------------" ) ; }
} public interface UserService { void add ( ) ;
}
@Component ( "userService" )
public class UserServiceImpl implements UserService { @DI ( "userDao" ) private UserDaoImpl userDao; @Override public void add ( ) { System . out. println ( "》》》 user service impl execute add method..." ) ; User user = new User ( "张三" , 25 ) ; userDao. addUser ( user) ; }
}
4. 定义异常信息类
4.1 InjectBeanException
public class InjectBeanException extends RuntimeException { public InjectBeanException ( ) { super ( ) ; } public InjectBeanException ( String message) { super ( message) ; }
}
4.2 NotExistsBean
public class NotExistsBean extends RuntimeException { public NotExistsBean ( ) { } public NotExistsBean ( String message) { super ( message) ; }
}
4.3 NotSupportMoreSuperInterface
public class NotSupportMoreSuperInterface extends RuntimeException { public NotSupportMoreSuperInterface ( ) { super ( ) ; } public NotSupportMoreSuperInterface ( String message) { super ( message) ; }
}
5. 测试自定义bean容器(带依赖注入)
5.1 新建测试类TestUser
public class TestUser { public static void main ( String [ ] args) { DefaultListableApplicationContext context = new DefaultListableApplicationContext ( "com.ypy.context" ) ; UserService userService = context. getBean ( "aaa" , UserServiceImpl . class ) ; UserDao userDao = context. getBean ( "userDaoImpl" , UserDao . class ) ; boolean existFlag = context. exists ( "aaa" ) ; System . out. println ( "UserService exists ? " + existFlag) ; System . out. println ( "从Bean容器中获取aaa对象地址: " + userService) ; System . out. println ( "从Bean容器中获取userDao对象地址: " + userDao) ; userService. add ( ) ; }
}
5.2 输出结果
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsMap store bean(name,obj) ===> (userDao,com.ypy.context.dao.impl.UserDaoImpl@2b193f2d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsTypeMap store bean(class,obj) ===> (UserDao,com.ypy.context.dao.impl.UserDaoImpl@2b193f2d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsMap store bean(name,obj) ===> (userService,com.ypy.context.service.impl.UserServiceImpl@7a81197d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: >>> objectsTypeMap store bean(class,obj) ===> (UserService,com.ypy.context.service.impl.UserServiceImpl@7a81197d)
一月 18, 2024 4:01:20 上午 com.sun.org.slf4j.internal.Logger warn
警告: <<< DI: Class UserServiceImpl of field named userDao is injected with value of com.ypy.context.dao.impl.UserDaoImpl@2b193f2d from objectsMap, by value of annotation @DI
UserService exists ? false
从Bean容器中获取aaa对象地址: com.ypy.context.service.impl.UserServiceImpl@7a81197d
从Bean容器中获取userDao对象地址: com.ypy.context.dao.impl.UserDaoImpl@2b193f2d
》》》 user service impl execute add method...------------------>>>执行UserDaoImpl中的addUser方法开始<<<<------------------名字 年龄张三 25
------------------>>>执行UserDaoImpl中的addUser方法完毕<<<<------------------Process finished with exit code 0