对IOC和AOP的概念了解清楚了,那么如何运用它们呢?
这里我们来通过一个银行转帐的demo来进行自定义IOC以及AOP的实现。
首先,我们实体类代码如下:
public class BankAccount {
//卡号
private String cardNo;
//姓名
private String name;
//余额
private int money;
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
dao层代码
public interface BankAccountDao {
//查询
BankAccount query(String carNo) throws SQLException;
//更新
void update(BankAccount to) throws SQLException;
}
service层:
public interface TransferService {
//转账
void transfer(String fromCardNo, String toCardNo, int money) throws SQLException;
}
service实现类:
public class TransferServiceImpl implements TransferService {
//转账具体实现
@Override
public void transfer(String fromCardNo, String toCardNo, int money) throws SQLException {
try {
BankAccountDao bankAccountDao=new BankAccountDaoImpl();
BankAccount from = bankAccountDao.query(fromCardNo);
BankAccount to = bankAccountDao.query(toCardNo);
from.setMoney(from.getMoney() - money);
to.setMoney(to.getMoney() + money);
bankAccountDao.update(to);
bankAccountDao.update(from);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
以上业务代码中,可以看出在 service实现类中,要想对对象进行持久化操作,则必须要new一个Dao层实现类的对象,这就造成了类TransferServiceImpl与类BankAccountDaoImpl之间耦合,如果业务比较复杂,那么所有的操作都需要把Dao层对象new出来,这就不利于系统代码到维护。
那么,我们怎么样来实现IOC来管理对象呢?
IOC既然帮我们new对象,那么需要new哪个对象肯定需要告诉容器,
这些我们可以在配置文件中进行约定,然后在加载的时候,容器读取到配置文件进行获取。
那么,这些new出来后,肯定需要存储,在这里我们用一个 HashMap集合进行对象的存储。
下面,我们先创建一个配置文件,取名 beans.xml,
根节点为 < beans >
字节点 < bean > 代表每个要管理到对象
< bean>中
id :类的标记,当作map中获取bean的key
class:全类限定名,然后可以通过反射来实现对象的实例化
如果对象A中包含另外一个对象B的时候呢?
我们在每个< bean>中添加子节点< property>来维护对象之间的依赖关系
< property>中:
name:代表着依赖对象中对名称,我们可以通过set方法注入,所以这里要和set方法名称去掉set后一致就行了
ref:告诉容器,这个要注入的对象的key
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<!--数据库连接工具类-->
<bean id="connectionUtils" class="com.lcg.edu.utils.ConnectionUtils">
</bean>
<!--dao-->
<bean id="bankAccountDao" class="com.lcg.edu.dao.impl.BankAccountDaoImpl">
<property name="ConnectionUtils" ref="connectionUtils"></property>
</bean>
<!--service-->
<bean id="transferService" class="com.lcg.edu.service.impl.TransferServiceImpl">
<property name="BankAccountDao" ref="bankAccountDao"></property>
</bean>
<!--事务管理器-->
<bean id="transactionManager" class="com.lcg.edu.utils.TransactionManager">
<property name="ConnectionUtils" ref="connectionUtils"></property>
</bean>
<!--代理对象工厂-->
<bean id="proxyFactory" class="com.lcg.edu.factory.ProxyFactory">
<property name="TransactionManager" ref="transactionManager"></property>
</bean>
</beans>
都准备好了以后,那么就新建一个BeanFactory工厂类,进行管理对象。
BeanFactory有两个任务,
* 任务一:读取解析xml,通过反射技术实例化对象并且存储待用(map集合)
* 任务二:对外提供获取实例对象的接口(根据id获取)
public class BeanFactory {
/**
* 任务一:读取解析xml,通过反射技术实例化对象并且存储待用(map集合)
* 任务二:对外提供获取实例对象的接口(根据id获取)
*/
//bean容器
private static Map<String, Object> map = new HashMap();
//任务1,解析加载xml配置到map中
static {
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
//解析xml
Document document = saxReader.read(resourceAsStream);
Element rootElement = document.getRootElement();
//解析bean
List<Element> beanList = rootElement.selectNodes("//bean");
for (Element element : beanList) {
//获取bean id
String id = element.attributeValue("id");
//获取bean class 全类限定名
String aClass = element.attributeValue("class");
//获取到类到Class对象
Class<?> clazz = Class.forName(aClass);
//反射创建对象
Object o = clazz.newInstance();
//存入map
map.put(id, o);
}
//遍历 引用对象,依赖注入
List<Element> propertyList = rootElement.selectNodes("//property");
for (Element element : propertyList) {
String name = element.attributeValue("name");
String ref = element.attributeValue("ref");
//获取父节点
Element parent = element.getParent();
String parentId = parent.attributeValue("id");
Object o = map.get(parentId);
Method[] methods = o.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals("set" + name)) {
method.invoke(o, map.get(ref));
}
}
map.put(parentId, o);
}
} catch (DocumentException | ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//任务二:对外提供获取实例对象的接口(根据id获取)
public static Object getBean(String beanId) {
return map.get(beanId);
}
}
这样一来,我们就可以在配置文件中配置依赖关系,在代码体现中,就接声明使用对象。
那么这时候就可以改造一下service对实现类:
这时候,业务逻辑中就不用进行new一个Dao层对象出来,而是直接声明一个对象,然后提供set方法,由系统加载的时候,直接根据配置文件进行依赖注入一个对象
public class TransferServiceImpl implements TransferService {
private BankAccountDao bankAccountDao;
public void setBankAccountDao(BankAccountDao bankAccountDao) {
this.bankAccountDao = bankAccountDao;
}
@Override
public void transfer(String fromCardNo, String toCardNo, int money) throws SQLException {
try {
BankAccount from = bankAccountDao.query(fromCardNo);
BankAccount to = bankAccountDao.query(toCardNo);
from.setMoney(from.getMoney() - money);
to.setMoney(to.getMoney() + money);
bankAccountDao.update(to);
bankAccountDao.update(from);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}