本文在参考资料的基础上进行阐述的,部分内容来自参考文章。
要了解控制反转( Inversion of Control ), 我觉得有必要先了解软件设计的一个重要思想:依赖倒置原则(Dependency Inversion Principle )。
假如我们现在需要造一辆车,所需要的依赖关系如下:
用代码来表示就是
上面车的轮子尺寸都是 size = 30 , 现在希望轮子的尺寸可以是动态,那么修改代码如下,
相应的 car 的代码修改如下 ,
可以看到这样我们需要自底而上去修改每个类,这样的代码是糟糕的,而且很难维护, 这时我们需要控制反转( ioc ), 及上层控制下层,而不是下层控制着上层。我们用依赖注入(Dependency Injection)这种方式来实现控制反转。所谓依赖注入,就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”。
那么到底依赖注入和控制反转到底是什么关系?
依赖倒置是原则,为了贯彻这个原则,确定控制(ioc )的思路,运用依赖注入的方法, 第三方容器在后面讲。
OK,现在知道了问题所在,如何解决呢?如何运用上依赖注入(DI)方法呢? 一般来说,依赖注入有三种方法, 构造方法注入,定义为接口,setting 方法注入, 其中setting方法和构造很相似,也很好理解,定义为接口,好处很明显,只要继承接口, 那么最终实现类就可以用很多,我们下面使用构造方法实现依赖注入看看。
这种设计模式还有利于不同组的协同合作和单元测试:比如开发这四个类的分别是四个不同的组,那么只要定义好了接口,四个不同的组可以同时进行开发而不相互受限制;而对于单元测试,如果我们要写Car类的单元测试,就只需要Mock一下Framework类传入Car就行了,而不用把Framework, Bottom, Tire全部new一遍再来构造Car。
作者:Sevenvidia
链接:https://www.zhihu.com/question/23277575/answer/169698662来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
问题解决了,很好,刚才那张图不是还有个容器的东西吗,依赖注入容器到底是什么呢?以上面的例子,将创建对象的地方封装成一个容器,请看
还是生产这个 Car , 经过依赖注入容器的方法的有是怎么样的呢?
我们再回想一下Spring ,看一下下图代码
1 @Configuration 2 @EnableCaching 3 public class RedisConfiguration extends CachingConfigurerSupport { 4 5 private static Logger logger = LoggerFactory.getLogger(RedisConfiguration.class); 6 7 8 @Autowired 9 private JedisConnectionFactory jedisConnectionFactory; 10 11 12 //缓存管理器 13 @Bean 14 public RedisCacheManager cacheManager(JedisConnectionFactory jedisConnectionFactory) { 15 return RedisCacheManager.create(jedisConnectionFactory); 16 } 17 18 @Bean 19 public StringRedisTemplate getRedisTemplate(){ 20 StringRedisTemplate template = new StringRedisTemplate(); 21 template.setConnectionFactory(jedisConnectionFactory); 22 return template; 23 } 24 }
代码中的 JedisConnectFactory
1 @PropertySource("classpath:application.properties") 2 @Configuration 3 public class JedisRedisConfig { 4 @Value("${spring.redis.host}") 5 private String host; 6 @Value("${spring.redis.port}") 7 private int port; 8 @Value("${spring.redis.password}") 9 public String password; 10 @Value("${spring.redis.jedis.pool.max-active}") 11 private int maxActive; 12 @Value("${spring.redis.jedis.pool.max-wait}") 13 private long maxWaitMillis; 14 @Value("${spring.redis.timeout}") 15 private int timeout; 16 17 18 @Bean 19 JedisConnectionFactory jedisConnectionFactory() { 20 RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(host, port); 21 JedisConnectionFactory factory = new JedisConnectionFactory(configuration); 22 return factory; 23 } 24 25 @Bean 26 public JedisPool redisPoolFactory() { 27 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); 28 jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); 29 JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password); 30 return jedisPool; 31 } 32 33 34 }
第一段代码中,JedisConfiguration 类就可以拿来用了,等一下, JedisConnectFactory 还没实例化呢,只是在第二段代码中有返回一个也是 JedisConnectFactory ,实际上Spring 就是使用这个容器为我们储存了对象,当我需要使用时直接拿出来用就行了。
参考资料:
1.