`
lkjxshi
  • 浏览: 29183 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

从源码中理解spring依赖注入和动态代理

阅读更多

 

使用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>&gt; 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依赖注入底层详解

    Spring依赖注入是Spring框架的核心特性之一,它极大地简化了Java应用程序的开发,使得对象之间的依赖关系得以解耦,提高了代码的可测试性和可维护性。本文将深入探讨Spring依赖注入的底层实现机制。 首先,我们要...

    spring依赖注入的实现原理

    本篇文章将深入探讨Spring依赖注入的实现原理,以及如何通过源码理解和使用这一特性。 一、依赖注入简介 依赖注入的基本思想是,对象不应该负责创建或查找它所依赖的对象,而应该由外部容器(如Spring框架)来负责...

    spring依赖注入三种方式 测试源码

    通过阅读和理解这些源码,你可以更深入地了解Spring依赖注入的工作原理及其在项目中的具体使用。 在进行依赖注入时,Spring使用BeanFactory或ApplicationContext作为容器,负责创建、管理和装配Bean。容器读取配置...

    Spring学习笔记(6)----编码剖析Spring依赖注入的原理

    本篇学习笔记将深入剖析Spring依赖注入的原理,通过源码分析帮助我们理解这一核心机制。 首先,依赖注入允许我们解耦组件之间的关系,使得各个组件可以独立地进行开发、测试和维护。在Spring中,DI主要通过两种方式...

    Spring依赖注入的方式

    在Spring框架中,依赖注入(Dependency Injection,简称DI)是一种重要的设计模式,它使得对象之间的耦合度降低,提高了代码的可测试性和可维护性。本文将深入探讨Spring中的依赖注入方式,包括构造器注入、设值注入...

    spring学习:依赖注入的几种方式讨论

    在Spring框架中,依赖注入(Dependency Injection,简称DI)是一种重要的设计模式,它使得对象之间的耦合度降低,提高了代码的可测试性和可维护性。本文将深入探讨Spring中的依赖注入实现方式,以及如何通过样例文件...

    spring依赖注入例子

    Spring框架的依赖注入(Dependency Injection,简称DI)...通过阅读和分析这些代码,你可以更深入地理解Spring的依赖注入机制。在实际开发中,你可以根据需求调整配置,如添加数据库连接池、使用不同的数据访问技术等。

    Spring 控制反转 依赖注入

    **Spring 框架中的控制反转 (IoC) 和依赖注入 (DI)** 在软件开发中,控制反转(Inversion of Control,简称IoC)是一种设计原则,它将对象的创建和管理权从代码中剥离出来,转交给一个外部容器(如Spring框架)。...

    Spring依赖注入使用setter设注入demo

    在提供的压缩包文件`SpringIOCTest1`中,很可能包含了上述步骤的实现,包括`MyService`和`MyRepository`的源代码,以及配置文件`beans.xml`。运行这个示例,你可以看到如何通过setter注入使`MyService`能够使用`...

    使用反射和注解模拟Spring的依赖注入

    我们将深入探讨反射和注解这两个关键概念,以及它们如何在模拟依赖注入中发挥作用。 首先,让我们理解反射的概念。反射是Java提供的一种能力,允许程序在运行时检查和操作类、接口、方法和字段。在Java中,`java....

    Spring依赖注入使用构造设注入demo

    本篇将详细讲解如何使用构造器注入作为Spring依赖注入的一种方式,并通过一个完整的可运行示例——"SpringIOCTest2"来加深理解。 首先,理解依赖注入的概念。依赖注入允许我们不在类内部创建对象,而是通过外部源...

    自己的代码模拟spring的依赖注入

    在IT行业中,Spring框架是Java开发中的一个基石,尤其在控制反转(IoC)和依赖注入(DI)方面。依赖注入是一种设计模式,它允许我们解耦组件,提高代码的可测试性和可维护性。Spring框架通过IoC容器来实现DI,让我们...

    Spring依赖注入DI.zip

    下面我们将深入探讨Spring依赖注入的概念、工作原理以及如何在实践中应用。 1. **依赖注入概念**: - 依赖:一个类对另一个类的使用称为依赖。 - 注入:将依赖的对象传递给需要它的类,而不是由类自己去创建或...

    spring源码中英文注释

    通过阅读源码和注释,我们可以更清晰地了解Spring如何管理依赖注入、AOP(面向切面编程)、事务管理、上下文以及其他的特性。 1. **依赖注入(Dependency Injection, DI)**:Spring的核心特性之一,允许组件之间...

    Spring Ioc(依赖注入)入门例子--属性注入

    回到我们的例子,`src`文件夹可能包含了示例的源代码,包括Spring配置文件和相关的Java类。这些代码会展示如何在Spring环境中配置和使用属性注入。通过阅读这些源码,我们可以学习如何定义bean,声明依赖,以及如何...

    第三章 Spring4 依赖注入

    在Spring框架中,依赖注入(Dependency Injection,简称DI)是一种核心的设计模式,它允许我们创建松耦合的代码,提高软件的可测试性和可维护性。Spring4版本进一步优化了这一特性,使其更加灵活和强大。本篇文章将...

    Spring 依赖注入 构造方法注入

    NULL 博文链接:https://zhangyulong.iteye.com/blog/856986

    springIOC控制反转 依赖注入实例

    在传统的程序设计中,我们通常手动创建对象并管理它们之间的依赖关系,而在Spring中,这些任务由IOC容器来处理,实现了从依赖管理到依赖注入的转变。 控制反转(IOC)意味着应用程序不再直接创建对象,而是将对象的...

    Spring.net(依赖注入应用)

    压缩包文件`SpringNet_Lesson6`可能包含一系列教程或示例代码,用于帮助学习Spring.NET的依赖注入和实际应用。建议结合这个资源,通过实践进一步理解Spring.NET的功能和使用方法。 总结来说,Spring.NET 是一个强大...

Global site tag (gtag.js) - Google Analytics