使用DAO层对实体进行操作:对DAO实现类,日志功能实现类,事务类进行依赖注入。很多人初学者可能会问,为什么要使用AOP对日志和事物实现管理,下面例子会有说明。当然以下例子只是针对spring如何实现AOP作出的说明,实际运用上可以使用xml进行配置统一管理。
1:首先是实体类 User.java
public class User {
private static final long serialVersionUID = -3061461829571439706L;
private String username; private int age;
public User() {
super();
}
public User(String username, int age) {
super();
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2:数据访问层分别有UserDao.java
public interface UserDao {
public void create(User user);
public void delete(User user);
}
3:它的实现类UserDaoImpl.java
public class UserDaoImpl implements UserDao, UserDao2 {
private static Logger logger = Logger.getLogger(UserDaoImpl.class);
@Override
public void create(User user) {
logger.debug("invoke create(user): username=" + user.getUsername()
+ ", age=" + user.getAge());
}
@Override
public void delete(User user) {
logger.debug("invoke delete(user): username=" + user.getUsername()
+ ", age=" + user.getAge());
}
}
4:日志接口类Advice.java
public interface Advice {
public void before(Method method, Object[] args);
public void after(Method method, Object[] args);
}
5:日志实现类LogAdvice.java(当然也可以是事务实现类,反正该类的目的就要能够在目标DAO方法前后发生。
public class LogAdvice implements Advice {
private static Logger logger = Logger.getLogger(LogAdvice.class);
@Override
public void before(Method method, Object[] args) {
logger.debug("LogAdvice before: current invoking method name:"
+ method.getName());
}
@Override
public void after(Method method, Object[] args) {
logger.debug("LogAdvice after: current invoking method name:"
+ method.getName());
}
}
6.写完需要拦截实现的方法后,就要进行动态代理类的编写了。要点:实现InvocationHandler接口的invoke方法,日志等实现接口的调用发生在代理对象前后。 InvocationHandlerImpl.java
class InvocationHandlerImpl implements InvocationHandler {
private Object target;
private List<advice> advices = new ArrayList<advice>();
public InvocationHandlerImpl() {
super();
}
public InvocationHandlerImpl(Object target) {
super();
this.target = target;
}
public InvocationHandlerImpl(Object target, List<advice> advices) {
super();
this.target = target;
this.advices.addAll(advices);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
for (Advice advice : advices) {
advice.before(method, args);
}
Object result = method.invoke(target, args);
for (Advice advice : advices) {
advice.after(method, args);
}
return result;
}
public void setTarget(Object target) {
this.target = target;
}
public void addAllAdvice(List<advice> advices) {
this.advices.addAll(advices);
}
public void addAdvice(Advice advice) {
this.advices.add(advice);
}
public void removeAdvice(Advice advice) {
this.advices.remove(advice);
}
}
7.最关键的一步来了,编写Bean工厂,为什么spring能通过读取XML文件的BEAN动态实例化类呢,下面的类就体现了JAVA的反射技术,每个类都有共同的CLASS对象。 Object beanInstance = Class.forName(beanClass).newInstance(); 这句话就是通过BEAN的名字,即XML中对应的ID实例化改类的方法,其中这里生成了DAO和日志接口实现类的对象,并在最后一个方法中通过动态代理实现spring的AOP。
public class BeanFactory {
private static final Logger logger = Logger.getLogger(BeanFactory.class);
private Map<string object> beanFactory = new HashMap<string object>();
public BeanFactory() {
this("beans.xml");
}
public BeanFactory(String configFilePath) {
try {
parseConfigurationFile(configFilePath);
}catch (Exception e) {
logger.error("error happen.it's " + e.getMessage());
e.printStackTrace();
}
}
public Object getBean(String beanName) {
return beanFactory.get(beanName);
}
public <t extends object> T getBean(Class<t> clazz) {
for (Object bean : beanFactory.values()) {
if (bean.getClass() == clazz)
return (T) bean;
}
throw new RuntimeException("bean of " + clazz.getName() + " don't find.");
}
private void parseConfigurationFile(String configFilePath) throws Exception {
InputStream inStream = this.getClass().getClassLoader().getResourceAsStream(configFilePath);
SAXReader reader = new SAXReader();
Document document = null;
try {
logger.debug("start parse document.");
document = reader.read(inStream);
} catch (DocumentException e) {
e.printStackTrace();
}
if (document == null) {
throw new RuntimeException(configFilePath + " parse failed.");
}
Element root = document.getRootElement();
logger.debug("root element is:" + root.getName());
List<element> beanEles = root.elements("bean");
Map<string list> beanAdvices = new HashMap<string list>();
getOriginalBeans(beanEles, beanAdvices);
injectAdvice(beanAdvices);
}
private void getOriginalBeans(List<element> beanEles, Map<string list> beanAdvices)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
for (Element beanElement : beanEles) {
String beanName = beanElement.attributeValue("id");
String beanClass = beanElement.attributeValue("class");
Object beanInstance = Class.forName(beanClass).newInstance();
beanFactory.put(beanName, beanInstance);
List<element> adviceElements = beanElement.elements("advice");
if (adviceElements.isEmpty()) {
continue;
}
List<string> adviceList = new ArrayList<string>();
for (Element adviceElement : adviceElements) {
String adviceRef = adviceElement.attributeValue("ref");
adviceList.add(adviceRef);
}
beanAdvices.put(beanName, adviceList);
}
}
private void injectAdvice(Map<string list>> beanAdvices) {
for (Entry<string list> beanAdvice : beanAdvices.entrySet()) {
String beanName = beanAdvice.getKey();
List<string> adviceNames = beanAdvice.getValue();
Object bean = beanFactory.get(beanName);
Class[] superInterfaces = bean.getClass().getInterfaces();
List<advice> advices = new ArrayList<advice>();
for (String adviceName : adviceNames) {
advices.add((Advice) beanFactory.get(adviceName));
}
InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(bean, advices);
Object beanProxy = Proxy.newProxyInstance(BeanFactory.class.getClassLoader(),
superInterfaces, invocationHandler); beanFactory.put(beanName, beanProxy);
}
}
}
8.XML文件,所需要依赖注入的类都在下面记录
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="com.spring.framework.foundation.UserDaoImpl">
<advice id="logAdvice" ref="logAdvice"></advice>
</bean>
<bean id="userDao2" class="com.spring.framework.foundation.UserDaoImpl"></bean>
<bean id="logAdvice" class="com.spring.framework.advice.LogAdvice">
</bean>
</beans>
当去掉<advice id="logAdvice" ref="logAdvice"></advice>后,就不会产生日志文件,也不会注入日志实现类。
在此,已经简单的介绍了spring 的IOC和AOP的实现机制,其实我也是大致的了解,并没有参透其中的深层原理,待续。。。
分享到:
相关推荐
spring 依赖注入三种方式测试源码,测试细节参考博文http://blog.csdn.net/u010679383/article/details/71305400
NULL 博文链接:https://zhangyulong.iteye.com/blog/856986
NULL 博文链接:https://huangminwen.iteye.com/blog/1041743
NULL 博文链接:https://matchless1688.iteye.com/blog/1038302
NULL 博文链接:https://shmilyaw-hotmail-com.iteye.com/blog/2169569
NULL 博文链接:https://coolszy.iteye.com/blog/512193
Spring依赖注入 PPT以及源码简单讲解Spring中的依赖注入
NULL 博文链接:https://zmx.iteye.com/blog/688299
NULL 博文链接:https://slnddd.iteye.com/blog/1756411
Spring Boot依赖注入
对spring.net和微软企业库(Enterprise Library 4.1)的依赖注入性能做了一个测试。有详细的数据和源码。 结果和分析参考:http://blog.csdn.net/yangjian15/archive/2009/11/07/4782870.aspx
简单的Java依赖注入框架,代码量少,实现了依赖注入和AOP。适合Spring源码的初学者掌握其核心原理
springIOC 小例子 附带源码 适合新手学习
NULL 博文链接:https://1151461406.iteye.com/blog/2389894
第5章 动态代理和经典的Spring AOP 第6章 Spring 2.x AOP和AspectJ支持 第二部分 基础主题 第7章 Spring对JDBC的支持 第8章 Spring中的事务管理 第9章 Spring对ORM的支持 第10章 ...
4、源码分析-IOC容器的依赖注入 5、源码分析-IOC容器的高级特性 三阶段 Spring AOP的涉及原理及具体实践 SpringJDBC的涉及原理及二次开发 SpringMVC框架设计原理及手写实现 四阶段 Spring事务源码解析 需要其他...
通过手写模拟,了解扫描逻辑和依赖注入等底层源码工作流程 通过手写模拟,了解初始化机制工作流程 通过手写模拟,了解BeanDefinition、BeanPostProcessor的概念 通过手写模拟,了解Spring AOP的底层源码工作流程
NULL 博文链接:https://baobeituping.iteye.com/blog/964226
NULL 博文链接:https://136812218.iteye.com/blog/1591606