`

Spring学习

 
阅读更多
1. 模拟实现Spring.
为什么要使用Spring呢?先考虑下最常用的访问数据库的框架:
1)POJO层有一个类User
2)Service层有一个类UserService,里面有一个成员变量User u,一个addUser(User u)方法
3)DAO层用来访问数据库(数据库可以在MySQL和Oracle之间任意切换):有一个UserDao接口(里面有一个addUser(User u)方法),该接口下面有两个实现类UserDaoMySQL, UserDaoOracle, 分别实现了addUser方法。
这样,在UserService中调用DAO层来访问数据库的时候,需要在addUser方法中new一个具体实现的DAO. 如:UserDao dao = new UserDaoMySQL();
但当我们想要切换数据库到Oracle的时候,我们需要将这句代码改成UserDao dao = new UserDaoOracle();
这样代码耦合度高,且需要重新编译class.

Spring有效的解决了上述问题:将变化的部分放到XML文件里面,然后对XML文件做解析(通过ClassPathXmlApplicationContext类),这样可以实现:
1)动态为UserDao user实例化对象(通过反射来做到)
2)动态为UserService的成员变量User u赋值(通过反射来做到)

Spring的模拟实现:
1) 写一个beans.xml: 将变化的部分/需要动态实例化/需要依赖注入的部分放入XML中。
<beans>
<!-- userDaoImpl表示UserDaoImplMySQL的instance -->
<bean id="userDaoImpl" class="source.dao.impl.UserDaoImplOracle" />

<!-- userService表示UserService的instance -->
<bean id="userService" class="source.service.UserService" >
<!-- 把userDaoImpl赋值给UserService类的成员变量userDao -->
<property name="userDao" ref="userDaoImpl"/>
</bean>
</beans>
2) ClassPathXmlApplicationContext.java: 用于解析beans.xml
package source.spring;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

/*
* 用于解析spring中的beans.xml:将xml的内容解析后存到名为beans的map中
*/
public class ClassPathXmlApplicationContext implements BeanFactory
{

    private Map<String, Object> beans = new HashMap<String, Object>();

    // IOC Inverse of Control DI Dependency Injection
    public ClassPathXmlApplicationContext () throws Exception
    {
        SAXBuilder sb = new SAXBuilder();
        InputStream file = new FileInputStream("src/source/beans.xml");
        Document doc = sb.build(file); // 构造文档对象
        Element root = doc.getRootElement(); // 获取根元素HD
        List list = root.getChildren("bean");// 取名字为disk的所有元素
        for (int i = 0; i < list.size(); i++) {
            Element element = (Element)list.get(i);
            String id = element.getAttributeValue("id");
            String clazz = element.getAttributeValue("class");
            Object o = Class.forName(clazz).newInstance();
            System.out.println(id);
            System.out.println(clazz);
            beans.put(id, o);

            for (Element propertyElement : (List<Element>)element.getChildren("property"))
            {
                String name = propertyElement.getAttributeValue("name"); // userDAO
                String bean = propertyElement.getAttributeValue("ref"); // u
                Object beanObject = beans.get(bean);// UserDAOImpl instance

                String methodName = "set" + name.substring(0, 1).toUpperCase()
                    + name.substring(1);
                System.out.println("method name = " + methodName);

                Method m = o.getClass().getMethod(
                    methodName,
                    beanObject.getClass().getInterfaces()[0]);
                m.invoke(o, beanObject);
            }

        }

    }

    @Override
    public Object getBean (String id)
    {
        return beans.get(id);
    }

}

3)UserService.java: 把UserDao作为成员变量,并提供set,get方法
public class UserService
{
    UserDAO userDao;
   
    public UserDAO getUserDao ()
    {
        return userDao;
    }

    public void setUserDao (UserDAO userDao)
    {
        this.userDao = userDao;
    }

    public void saveUser(User u) {
        userDao.addUser(u);
    }
}

4) JUnit测试类UserServiceTest.java:
public class UserServiceTest
{

    @Test
    public void test () throws Exception
    {
        BeanFactory factory = new ClassPathXmlApplicationContext(); //解析xml, 通过反射做依赖注入。
        UserService service = (UserService)factory.getBean("userService");
        User u = new User();
        service.saveUser(u);
    }

}

这样,在需要切换数据库的时候,只需要修改beans.xml即可。且动态为UserService.java的成员变量UserDao实例化对象。

2. 什么是依赖注入(DI)/控制反转(IOC)?
1)依赖注入:对于UserService的成员变量userDao, 它是依赖于容器给它“注入”对象,所以叫依赖注入。
2)控制反转:对于UserService的成员变量userDao,原来是由代码做实例化,如UserDao userDao = new UserDaoImplMySQL(); 现在是由容易来控制实例化的过程,所以叫控制反转。

3. Annotation.
1)@Required:This annotation simply indicates that the affected bean property must be populated at configuration time. 即@Required修饰的setter方法必须系统初始化的时候被注入,否则报错。
2) @resource: 默认是byType
如果要指定byName, 可以这样用:
    @Resource(name="userDaoImpl")
    public void setUserDao (UserDAO userDao)
    {
        this.userDao = userDao;
    }

3) @Autowired: 在setter方法上面修饰,会自动注入,默认为byType.

@Autowired 和@Resource 的区别?
1. @Autowired属于Spring的;@Resource为JSR-250标准的注释,属于J2EE的。
2. @Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,例如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用:
@Autowired()
@Qualifier("baseDao")
private BaseDao baseDao;
3. Resource,默认安装名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="userDaoImpl")
public void setUserDao (UserDAO userDao)

注:@Resource(name="userDaoImpl") 等价于:
@Autowired()
@Qualifier("userDaoImpl")

4. annotation与xml的优缺点比较:
1) annotation比xml更简单直观。
2) 但annotation与java源代码紧耦合,如果要修改注入规则,则需要修改java代码,不如xml解耦性更好

5. AOP前瞻:为什么说组合比继承更灵活?
如果要在userDaoImplOracle.java 的addUser方法中加入新的逻辑,此时有两种方式:
1)写一个类userDaoImplOracle2.java来继承userDaoImplOracle.java,然后在userDaoImplOracle2.java的addUser方法中Override其父类的addUser方法,但使用继承使得与父类紧耦合:修改父类的话,也需要修改子类,且子类不能继承其他的类。
2)使用组合关系:userDaoImplOracle3.java:
在其中加入成员变量private UserDao userDao = new UserDaoImplOracle();
然后在其addUser方法中调用userDao.addUser方法。

6. 动态代理:AOP的底层实现原理
JDK的动态代理:目的是在某一层的系列的方法前执行..., 在方法后执行...
1)LogInterceptor作为实现了InvocationHandler的接口的类。
public class LogInterceptor implements InvocationHandler
{
    private Object target;
   
    public Object getTarget ()
    {
        return target;
    }

    public void setTarget (Object target)
    {
        this.target = target;
    }

    private void before (Method method)
    {
        System.out.println(method.getName() + " before...");
    }

    @Override
    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
    {
        before(method);
        method.invoke(target, args);
        after(method);
        return null;
    }
   
    private void after (Method method)
    {
        System.out.println(method.getName() + " after...");
    }

}
2)这样调用:
    @Test
    public void test () throws Exception
    {
        UserDAO userDao = new UserDaoImplOracle();
        LogInterceptor handler = new LogInterceptor();
        handler.setTarget(userDao);
        UserDAO userDaoProxy = (UserDAO)Proxy.newProxyInstance(
            userDao.getClass().getClassLoader(),
            userDao.getClass().getInterfaces(),
            handler);
        userDaoProxy.addUser(new User());
    }

这样,在执行userDaoProxy.addUser方法的时候,首先找到handler,然后执行其invoke方法。
分享到:
评论

相关推荐

    spring 学习

    由于提供的文件内容中存在大量重复的网址信息,并没有实际的教学内容或者相关知识点,我将从标题“spring 学习”出发,结合描述“通过搭建基本的工程,从中学习spring的原理”来详细阐述Spring框架的相关知识点。...

    spring学习资料大全

    以下是对"Spring学习资料大全"的详细解析: 1. **Spring框架基础**: - **依赖注入(Dependency Injection,DI)**:Spring的核心特性之一,它允许开发者在运行时通过XML配置或注解方式来管理对象间的依赖关系,...

    spring学习.zip

    本资源集合围绕"spring学习.zip",提供了多本深入讲解Spring及其相关技术的电子书籍,旨在帮助读者深入理解和掌握Spring生态。 1. **《深入实践Spring Boot.陈韶健.pdf》**:这本书详细介绍了Spring Boot,它是...

    spring学习

    在"spring学习"的资源包中,我们看到三个关于"第四章 Spring的基本用法"的PPT文件,分别是"第一次"、"第三次"和"第二次"。虽然顺序可能有些混乱,但我们可以从中提取出一系列关键知识点。 1. **依赖注入**:Spring...

    Spring学习笔记 自我总结

    spring学习笔记

    spring学习资料,精心总结,不可错过,速领!.zip

    这个"spring学习资料,精心总结,不可错过,速领!.zip"压缩包显然是为那些想要深入理解Spring框架的人准备的。以下是压缩包内可能包含的一些关键知识点,以及它们在实际开发中的应用和重要性: 1. **IoC...

    Spring学习资料文档合集

    Spring学习资料文档合集,包含 spring2.0-reference_RC2.1_zh_cn spring_reference_inchinese_m2 SpringGuide Spring基础教程 spring框架,技术详解及使用指导

    Spring学习笔记&源码

    本资料“Spring学习笔记&源码”是基于网易云课堂黑马程序员的Spring四天精通课程,旨在帮助学习者深入理解和实践Spring框架。 笔记部分可能会涵盖以下内容: 1. **Spring概述**:介绍Spring框架的历史、特点和主要...

    spring学习文档 适合新手

    spring学习文档 适合新手

    spring学习资料

    这个"spring学习资料"压缩包包含了多个文档,可以帮助我们深入理解并掌握Spring的核心概念和技术。 首先,"spring2.0-reference_final_zh_cn.chm"是Spring 2.0的中文参考手册,对于初学者来说非常宝贵。它详细介绍...

    Spring学习思维导图(仅供参考)

    Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图Spring学习思维导图...

    Spring学习笔记.xmind

    Spring学习笔记.xmind

    Spring学习手册

    【Spring学习手册】 Spring框架是Java开发中的一个核心组件,尤其在企业级应用开发中扮演着重要角色。它提供了一种全面的编程和配置模型,旨在简化开发过程并提高可测试性。本手册专为Spring的初学者设计,旨在帮助...

    spring学习文档

    Spring 学习文档 Spring 是一个Java企业级应用程序开发框架,它提供了一个通用的应用程序开发架构,帮助开发者更快速、更高效地开发企业级应用程序。本文档记录了学习 Spring 的过程,包括 Spring 的基础知识、...

    Spring学习笔记+学习源码.zip

    这份"Spring学习笔记+学习源码.zip"资源包含了深入学习Spring及其相关技术的知识点,以及实践代码,对提升Spring技能将大有裨益。 首先,我们来详细讨论Spring框架的主要组件和功能: 1. **依赖注入(Dependency ...

    超好的Spring 学习资料

    "超好的Spring学习资料"这个压缩包显然包含了深入理解并掌握Spring框架的关键资源,尤其是包含的《Spring in Action》这本书,是Spring学习的经典之作。 1. **Spring框架概述**:Spring是一个开源的Java平台,它...

    Spring学习笔记.zip

    根据提供的压缩包文件名,我们可以推测这是一个逐步学习Spring的系列笔记。从"Spring_day1"开始,可能涵盖了Spring的基础概念、环境搭建和基本配置。"Spring_day2"可能涉及了依赖注入和AOP的深入讲解。"Spring_day3...

    Java Spring学习路线.pdf

    上述提到的Spring学习路线涵盖了从基础到高级的多个方面,包括了IOC、AOP、JDBC模板的使用和事务管理等核心内容。掌握这些知识点对于高效开发高质量的Java后端应用至关重要。对于Java后台开发人员而言,深入学习和...

Global site tag (gtag.js) - Google Analytics