java反射
在运行状态中,对于任何一个对象,通过名字能够调用它的任意一个方法和属性,这种动态获取的信息以及动态动用对象的方法的功能,就成为反射机制。
简单分层开发中,逻辑处理类调用持久层的类方法,就要在逻辑处理类中添加引用。
/**
* 顾客类
* @author xl
*
*/
public class Customer {
//id
private Long id;
//名字
private String name;
//年龄
private int age;
public Long getId(){
return id;
}
public void setId(Long id){
this.id = id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
}
/**
* 客户的业务处理类
* @author xl
*
*/
public class CustomerService {
//添加持久化类的引用,此时是对类的引用
public CustomerDao customerDao;
//添加客户
public void add(Customer customer){
customerDao.save(customer);
};
public CustomerDao getCustomerDao(){
return customerDao;
}
public void SetCustomerDao(CustomerDao customerDao){
this.customerDao = customerDao;
}
}
/**
* 客户的持久化类
* @author xl
*
*/
public class CustomerDao {
//添加用户
public void save(Customer customer){
System.out.println("customer--saved!");
}
}
为了提高系统的灵活性,不再针对具体而对接口编程。
面对不同的数据库,就应该有不同的持久化类,对这样的需求建立抽象。
/**
* 客户的业务处理类
* @author xl
*
*/
public class CustomerService {
//添加持久化类的引用,此时是对 接口的引用
public CustomerDao customerDao = new CustomerDaoImplForMySql();
//添加客户
public void add(Customer customer){
customerDao.save(customer);
};
public CustomerDao getCustomerDao(){
return customerDao;
}
public void SetCustomerDao(CustomerDao customerDao){
this.customerDao = customerDao;
}
}
/**
* 客户的持久化接口
* @author xl
*
*/
public interface CustomerDao {
//添加用户
public void save(Customer customer);
}
/**
* 对mysql数据库持久化的类
* @author xl
*
*/
public class CustomerDaoImplForMySql implements CustomerDao {
@Override
public void save(Customer customer) {
System.out.println("mysql--customer--saved!");
}
}
/**
* 对orcale数据库进行持久化的类
* @author xl
*
*/
public class CustomerDaoImplForOrcale implements CustomerDao {
@Override
public void save(Customer customer) {
System.out.println("orcale--customer--saved!");
}
}
/**
* 测试类
* @author xl
*
*/
public class CustomerServiceTest {
/**
* 测试添加方法
*/
@Test
public void testAdd() {
CustomerService cs = new CustomerService();
Customer customer = new Customer();
cs.add(customer);
}
}
运行测试类:
以上两种实现,应对了对mysql和oracle两种数据库的进行持久化的变化。如果更换为oracle,那么只要将Service类中对Dao引用的实现改为oracle的就行了。
以上说明,针对接口编程使系统灵活了,应对了变化。但是不是完全的灵活,因为如果更换数据库的话,还需要改程序代码,重新编译。违背了对修改关闭的原则。
长篇累牍,终于到了反射。通过在xml配置文件里定义好使用哪个数据库,程序运行时加载、读取配置文件。根据配置文件中的值动态生成类,完成对数据库的持久化。
datasource.xml
<databases>
<database name="source" value="com.reflection.dao.impl.CustomerDaoImplForMySql"></database>
</databases>
/**
* 客户的业务处理类
* @author xl
*
*/
public class CustomerService {
//添加持久化类的引用,此时是对 接口的引用
public CustomerDao customerDao;
//添加客户
public void add(Customer customer){
customerDao.save(customer);
};
public CustomerDao getCustomerDao(){
return customerDao;
}
public void SetCustomerDao(CustomerDao customerDao){
this.customerDao = customerDao;
}
}
/**
* 读取XML配置文件
* @author xl
*
*/
public class XmlReader{
//定义Map容器
Map<String,Object> map = new HashMap<String,Object>();
public XmlReader() throws JDOMException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException{
SAXBuilder sb = new SAXBuilder();
//读取文件
Document doc = sb.build(XmlReader.class.getClassLoader().getResourceAsStream("datasource.xml"));
//获得根节点
Element el = doc.getRootElement();
List sourceList = el.getChildren("database");
for(int i=0;i<sourceList.size();i++){
Element e = (Element)sourceList.get(i);
String name = e.getAttributeValue("name");
String value= e.getAttributeValue("value");
//反射:通过名字拿到类
Object o = Class.forName(value).newInstance();
//放到容器中
map.put(name,o);
}
}
//通过key--name,拿到对应的value--dao的实现类
public Object getSource(String name){
return map.get(name);
}
}
/**
* 测试类
* @author xl
*
*/
public class CustomerServiceTest {
/**
* 测试添加方法
*/
@Test
public void testAdd() {
CustomerService cs = new CustomerService();
Customer customer = new Customer();
try {
XmlReader xr = new XmlReader();
CustomerDao customerDao = (CustomerDao)xr.getSource("source");
//通过set将dao的实现类添加到service中
cs.SetCustomerDao(customerDao);
cs.add(customer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行测试类,控制台输出:
在运行时,读取配置文件,动态决定持久化的类。即使用户想更改数据库,只要修改配置文件中value的值就可以。有了这样的规则,按着约定走,让系统更加的灵活,也正是体现了约定大约配置的原则。