首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

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

2012-08-27 
从源码中理解spring依赖注入和动态代理?使用DAO层对实体进行操作:对DAO实现类,日志功能实现类,事务类进行

从源码中理解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);@Overridepublic void create(User user) {logger.debug("invoke create(user): username=" + user.getUsername()+ ", age=" + user.getAge());}@Overridepublic 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);@Overridepublic void before(Method method, Object[] args) {logger.debug("LogAdvice before: current invoking method name:"+ method.getName());}@Overridepublic 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);}@Overridepublic 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" ref="logAdvice"></advice></bean>         <bean id="userDao2" ref="logAdvice"></advice>后,就不会产生日志文件,也不会注入日志实现类。

?在此,已经简单的介绍了spring 的IOC和AOP的实现机制,其实我也是大致的了解,并没有参透其中的深层原理,待续。。。

热点排行