Spring框架入门

一.模块划分

二.Spring的ICO实现的核心技术

三.ICO的模拟实现(重点)

       1.工厂实例化对象

                工厂的分类:简单工厂;工厂方法;抽象工厂(通用的工厂方法)

ICO工厂产生对象的方法:    

       2.XML解析

解析方式为DOM4J的解析方式,需要导入相应的架包

       3.反射

通过方式得到实体类的对象,然后通过method的invoke方法给属性赋值,具体的实现工厂为:

/**
 * 模拟ioc实例化对象的思路
 *   1.xml解析
 *   2.对象实例化
 *   3.对外提供getObj方法
 *      根据对象名获取value
 *   4.给属性赋值(依赖注入|装配)
 *      反射实现 set  方法赋值操作
 *
 */
public class SxtFactory_07 implements SxtFactory {

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

    private List<SxtBean> beans =new ArrayList<SxtBean>();

    public SxtFactory_07(String fileName) {
        this.parseXml(fileName);
        this.instanceBean();
        this.setSxtProperty();
    }

    /**
     * 给属性赋值
     */
    private void setSxtProperty() {
        try {
            if(beans.size()>0){
                for(SxtBean sxtBean:beans){
                    // 获取属性集合
                    List<SxtProperty> properties=sxtBean.getProperties();
                    if(null !=properties && properties.size()>0){
                        for(SxtProperty property:properties){
                            String id=property.getId();
                            // 首字母大写
                            id=id.toUpperCase().charAt(0)+id.substring(1);
                            String ref=property.getRef();
                            Class clazz=map.get(sxtBean.getId()).getClass();
                            Method method= clazz.getDeclaredMethod("set"+id,map.get(ref).getClass());
                            method.invoke(map.get(sxtBean.getId()),map.get(ref));
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void instanceBean() {
        try {
            if(beans.size()>0){
                for(SxtBean sxtBean:beans){
                    map.put(sxtBean.getId(),Class.forName(sxtBean.getClazz()).newInstance());
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * xml 解析
     * @param fileName
     */
    private void parseXml(String fileName) {
        /**
         * xml 解析
         */
        URL url= this.getClass().getClassLoader().getResource(fileName);
        if(null !=url){
            SAXReader saxReader=new SAXReader();
            try {
                Document document= saxReader.read(url);
                XPath xPath= document.createXPath("beans/bean");
                List<Element> elements= xPath.selectNodes(document);


                if(null!=elements && elements.size()>0){
                    for(Element element:elements){
                        xPath=document.createXPath("property");
                        // 匹配当前的元素
                        List<Element> subElements= xPath.selectNodes(element);
                        List<SxtProperty> properties=null;
                        SxtBean sxtBean= new SxtBean(element.attributeValue("id"),element.attributeValue("class"));
                        if(null !=subElements && subElements.size()>0){
                            properties=new ArrayList<SxtProperty>();
                            for(Element subElement:subElements){
                                SxtProperty property=new SxtProperty(subElement.attributeValue("id"),subElement.attributeValue("ref"));
                               properties.add(property);
                            }
                        sxtBean.setProperties(properties);
                        }


                       beans.add(sxtBean);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            System.out.println("文件未找到!!!");
        }
    }

    @Override
    public Object getObj(String name) {
        return map.get(name);
    }
}

spring.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <bean id="userService" class="com.shsxt.service.UserService">
        <!--
          id:属性名称
          ref:实例化的对象的id 唯一标识
        -->
        <property id="userDao" ref="userDao"></property>
        <property id="testService" ref="testService"></property>

       <!-- <property id="userDao" ref="userDao"></property>
        <property id="userDao" ref="userDao"></property>
        <property id="userDao" ref="userDao"></property>-->

    </bean>

    <bean id="accountService" class="com.shsxt.service.AccountService">
       <!-- <property id="userDao" ></property>-->
    </bean>
    <bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
    <bean id="testService" class="com.shsxt.service.TestService"></bean>
</beans>

四.IOC 扫描器模拟

1.获取扫描包的范围
                  com.shsxt02(直接给的的方式)
            2.获取指定包以及子包下的所有的class 文件(不考虑jar包)
                  C:\\java\workspace21\\ioc01\\src\main\\java\\com\\shsxt02\\dao\\UserDao.class
                  C:\\java\workspace21\\ioc01\\src\main\\java\\com\\shsxt02\\dao\\AccountDao.class
                   .....

/**
    * @Description:获取指定包以及子包下的所有的class 文件(不考虑jar包)
    * @Author: Mr Tong
    * @Date: 2018/9/26 21:48
    */
    public static void getAllClass(String pkg){
        // com/shsxt02
        URL url=Thread.currentThread().getContextClassLoader().getResource(replacePath(pkg));
        String basePath=url.getFile();
        String[] subFileStrs= new File(basePath).list();
        for(String str:subFileStrs){
            // 获取子目录地址
            String subFilePath=basePath+"/"+str;
            File subFile=new File(subFilePath);
            if(subFile.isDirectory()){
                getAllClass(pkg+"."+subFile.getName());
            }else{
                //System.out.println(basePath+"/"+subFile.getName());
                // com.shsxt02.controller.UserController
                // 存储包名-指定类的全路径
                clazzzz.add(pkg+"."+subFile.getName());
            }
        }


    }


            3.判断class 类级别上有没有标注指定注解
                   注解存在
                         实例化该对象:获取id 唯一标识

/**
    * @Description: 实例化对象的方法,
     * 判断class 类级别上有没有标注指定注解
     *     注解存在:
     *        实例化该对象:获取id 唯一标识
    * @Author: Mr Tong
    * @Date: 2018/9/26 21:47
    */
    private static void instanceBeans() {
        try {
            if(clazzzz.size()>0){
                for(String classStr:clazzzz){
                    classStr=classStr.replace(".class","");
                    SxtComponent sxtComponent=  Class.forName(classStr).getAnnotation(SxtComponent.class);
                    if(null !=sxtComponent){
                        Object obj=Class.forName(classStr.replace(".class","")).newInstance();
                        classStr= classStr.substring(classStr.lastIndexOf(".")+1);
                        String key=classStr.toLowerCase().charAt(0)+classStr.substring(1);
                        System.out.println(key);
                        map.put(key, obj);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

 4.依赖注入
                 * 获取map 中每个对象的 fields
                 * 获取字段级别的注解   SxtResource
                 * 调用field 的set方法实现注入

/**
     * 依赖注入
     * 获取map 中每个对象的 fields
     * 获取字段级别的注解   SxtResource
     * 调用field 的set方法实现注入
     */
    private static void execAutoWired() {
        try {
            if(null != map && !(map.isEmpty())){
                for(Map.Entry<String,Object> entry:map.entrySet()){
                    Class clazz = entry.getValue().getClass();
                    Field[] fields = clazz.getDeclaredFields();
                    System.out.println(fields + "~~~");
                    if(null != fields && fields.length>0){
                        for(Field field:fields){
                            //SxtComponent sxtComponent=  Class.forName(classStr).getAnnotation(SxtComponent.class);
                            SxtAutoWired sxtAutoWired = field.getAnnotation(SxtAutoWired.class);
                            System.out.println("sxtAutoWired");
                            if(null != sxtAutoWired){
                                field.setAccessible(true);
                                //field.set(entry.getValue(),map.get(sxtAutoWired.value()));
                            }
                        }
                    }
                }
                }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

五.依赖注入(装配)

  

六.作用域及生命周期

七.注解之bean的注入

对于 bean 的注入,除了使用 xml 配置以外,注解的配置简化开发的速度,使程序看上去更简洁。对于注解的解释, spring 对于注解有专门的解释器,对定义的注解进行解析,实现对应 bean 对象的注入, 反射技术实现

1.加入 spring-aop jar 包 spring-aop-4.3.2.RELEASE.jar

2.Xml 配置: 加入 context 命名空间 和 xsd 地址

3. 添加<context:annotation-config/> 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
</beans>

1.bean 的注入常用注解类型: 

 @Autowired 属性字段或 set 方法上
 @Resource 属性字段上或 set 方法上
区别: @Autowired 默认按 bean 的类型匹配 可以修改 按名称匹配 和@Qualifier 配合使用
         @Resource 默认按名称进行装配,名称可以通过 name 属性进行指定,如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行匹配注入,如果注解写在 setter 方法上默认取属性名进行装配。当找不到与名称匹配的 bean时才按照类型进行装配。 但是需注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。
          推荐使用@Resource 注解是属于 J2EE 的,减少了与 spring 的耦合。

2.Spring Ioc 容器自动扫描管理 bean

实际的开发中, bean 的数量非常多,采用手动配置 bean 的方式已无法满足生产需要, spring 这时候同样提供了扫描的方式,对扫描到的 bean 对象统一进行管理,简化开发配置,提高开发效率。

扫描指定的包:

<context:component-scan base-package="com.shsxt"/>

开发中建议(开发中的一种约定)

  1.  Dao 层:@Repository
  2. Service 层:@Service
  3. 视图控制层:@Controller
  4. 如果对于开发的类实在不明确到底属于哪个层,可以使用@Component 注解定义。@Resource的装配顺序:
  5. @Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配指定了name或者type则根据指定的类型去匹配bean,指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错


     



 

 

 


 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值