javareflectiondependency-injectioninversion-of-control

DI and IOC using core java


Is there a way to use core java/reflection to load create dependency objects and set it to other as a dependency?

I could do it, but the facing issues while dealing with nested beans.

Ultimately, I am not interested to use spring for the simple usage.

Any help much appreciated.


Solution

  • I generally use Spring or Micronaut frameworks but there may be times when manual DI makes sense - e.g. an AWS Lambda in Java which needs to be as slick / minimal and / run as quickly as possible.

    You mentioned dealing with nested beans was a pain, the solution I went for is to create a single class to hold all the instances e.g. AppContext which has a private constructor, a single static instance which is accessible like:

    public class AppContext {
    
        private static AppContext appContext;
    
        public static AppContext getInstance() {
            if (appContext == null) {
                appContext = new AppContext();
            }
            return appContext;
        }
    
        private AppContext () {}
    
    }
    

    Now we can start adding our classes (Beans). If we were writing an application which e.g. performs file uploads we may have classes for service, mappers, DAO, etc:

        private AppProperties appProperties;
        private ObjectMapper objectMapper;
        private UploadService uploadService;
        private UploadMapper uploadMapper;
        private UploadDao uploadDao;
        private S3Client s3Client;
    

    Each of these fields will have a no-args accessor method e.g.

    
        public AppProperties getProperties() {
            if (this.appProperties == null) {
                this.appProperties = new AppProperties();
            }
            return this.appProperties;
        }
    
       public ObjectMapper getObjectMapper() {
            if (this.objectMapper == null) {
                return JsonMapper
                        .builder()
                        .addModule(new JavaTimeModule())
                        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                        .build();
            }
            return this.objectMapper;
        }
    
        public UploadService getUploadService() {
            if (this.uploadService == null) {
                this.uploadService = new UploadService(getUploadDao(), getUploadMapper());
            }
            return this.uploadService;
        }
    }
    

    All these instances are lazy loaded and some classes are very simple e.g. AppProperties and ObjectMapper but others e.g. UploadService requires 2 injected classes/interfaces UploadDao / UploadMapper, these will have further methods too e.g.

        public UploadDao getUploadDao() {
            if (this.uploadDao == null) {
                this.uploadDao = new UploadDaoS3(getS3Client());
            }
            return this.uploadDao;
        }
    
        public S3Client getS3Client() {
            if (this.s3Client == null) {
                S3ClientBuilder s3ClientBuilder = S3Client.builder();
                // additional config ...
                this.s3Client = s3ClientBuilder.build();
            }
            return this.s3Client;
        }
    
        public UploadMapper getUploadMapper() {
            if (this.uploadMapper == null) {
                this.uploadMapper = new UploadMapperImpl();
            }
            return this.uploadMapper;
        }
    

    As you can see the UploadDao, UploadMapper are interfaces and UploadDaoS3 and UploadMapperImpl are the implementations.

    To access any of these instances (normally the high level service class) is as simple as:

       UploadService service = AppContext.getInstance().getUploadService();
       service.uploadFile( ... );
    

    Note, all the examples use constructor injection but we can of course use setter injection too for optional fields.

    This solution is manual and reflection free but will work if speed / absolute minimum number of libraries is important.