spring的控制反转
在开发中,我们常使用这样的项目结构,在没有使用spring框架的时候,通常使用这样的代码去实例化一个对象
IProductDao productDao1 = new ProductDaoImpl();
使用spring之后,常使用下面的方式进行创建对象。
- 自动装配,使用spring
@Autowired
注解的方式
@Autowired
private IProductDao productDao1;
- 使用构造器的方式注解
private IProductDao productDao1;
@Autowired //构造器注入
private (IProductDao dao) {
this.productDao1 = dao;
}
使用spring之后,=
号后面的内容就不要我们在进行书写了。把创建的对象权利交给了spring容器了,这就是spring的控制反转。
实现方式1
spring内部其实就是一个大的工厂,首先可以通过创建工厂的方式来进行创建。
public class DaoFactory {
/**构造器私有化*/
private DaoFactory(){
}
/**创建一个Dao对象*/
public static Object createDao(String daoName){
if ("productDao".equals(daoName)){
return new ProductDaoImpl();
}else if("userDao".equals(daoName)){
return new UserDaoImpl();
}
return null;
}
public static void main(String[] args) {
}
}
但是,这种创建方式效率不够高,硬编码的方式,可移植化低,只能创建少数几个类型的对象。
实现方式2
通过配置dao.properties
文件的方式,将bean信息写入配置文件中,然后根据反射的方式进行创建对象。
配置文件文件内容
productDao=factory.dao.impl.ProductDaoImpl
userDao=factory.dao.impl.UserDaoImpl
public class DaoFactory {
/*** 构造器私有化*/
private DaoFactory(){ }
//不需要外部进行访问
private static Properties pros = new Properties();
// 在静态代码块中加载
static{
try {
pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("factory/config/dao.properties"));
} catch (Exception e) { e.printStackTrace(); }
}
public static Object createDao(String daoName){
//根据key拿到相应value,创建这个类的全限定名称
String className = pros.getProperty(daoName);
//拿到全限名,根据反射创建对象
try{
Class<?> clz = Class.forName(className);
return clz.newInstance();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
IProductDao productDao =(IProductDao) DaoFactory.createDao("productDao");
System.out.println(productDao);
IUserDao userDao = (IUserDao) DaoFactory.createDao("userDao");
System.out.println(userDao);
}
}
但是使用这种方式的缺陷就是,通过工厂创建的方式,需要使用强制转换的方式。能够使用泛型方法来解决这个问题。
将上面的函数修改为
public static <T> T createDao(String daoName){
//根据key拿到相应value,创建这个类的全限定名称
String className = pros.getProperty(daoName);
//拿到全限名,根据反射创建对象
try{
Class<?> clz = Class.forName(className);
return (T)clz.newInstance();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
相同类型的对象,使用一个缓存。
public static <T> T createDao(String daoName) {
//根据key拿到相应value,创建这个类的全限定名称
String className = pros.getProperty(daoName);
//拿到全限名,根据反射创建对象
try {
T t = (T) cacheMap.get(daoName);
if (t == null) {
Class<?> clz = Class.forName(className);
t = (T) clz.newInstance();
//把对象放到缓存里面去
cacheMap.put(daoName, t);
}
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}