Spring Framework

     SPRING FRAMWORK

1. 框架回顾

1.1. Spring 概述

1. Spring 是什么?(框架,半成品)

2. Spring 能解决什么问题(面向对象,面向切面,面向服务)

3. Spring 框架核心?(IOC,AOP,MVC,…)

 

个人认为:Spring 最强大是它的资源整合能力。

 

1.2. Spring IOC 概述

1. IOC是什么?(控制反转:由spring构建对象,管理对象依赖)

2. IOC 应用优势?(解耦,更好的管理对象,使用系统资源)

3. IOC 的核心?(工厂,配置,依赖注入)

4. IOC 编程步骤?(类,配置,获取)

 

1.3. Spring IOC 编程

1. Spring Bean对象初始化,作用域,声明周期,延迟加载

1) Bean类型的编写(修饰符,构造方法)

2) Bean 的配置(applicationContext.xml)

3) Bean 的作用域(singleton,prototype)

4) Bean 的生命周期(生命周期方法的使用)

5) Bean 的延迟加载(局部lazy-init,全局 default-lazy-init)

 

2. Spring Bean依赖(依赖注入,自动装配)

1) 依赖注入(DI)的定义(通过spring为类中的属性注入值)

2) 依赖注入的实现(set注入,构造注入)

3) 依赖注入中的集合值的注入(数组,list,set,map)

4) 依赖注入中的自动装配(未讲)

 

2. Spring Bean依赖

2.0.1. 依赖注入基础

重点了解set,构造注入的方式以及单个值如何实现注入。

2.0.2. 依赖注入进阶

重点了解集合类型值的注入,例如listhashmap,properties

案例1

定义一个相对复杂的对象

public class ComplexObject {

private String[] names;

private List<String> address;

private Map<String,Integer> map;

private Properties properties;

//set,get

}

在配置文件中配置此对象,并为属性注入值

 

<?xml version="1.0" encoding="UTF-8"?>

<beans 

    default-lazy-init="true"

    xmlns="http://www.springframework.org/schema/beans" 

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:mvc="http://www.springframework.org/schema/mvc"

    xmlns:util="http://www.springframework.org/schema/util"

    xmlns:jpa="http://www.springframework.org/schema/data/jpa"

    xsi:schemaLocation="  

       http://www.springframework.org/schema/beans   

       http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  

       http://www.springframework.org/schema/mvc   

       http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd   

       http://www.springframework.org/schema/tx   

       http://www.springframework.org/schema/tx/spring-tx-4.3.xsd   

       http://www.springframework.org/schema/aop

       http://www.springframework.org/schema/aop/spring-aop-4.3.xsd

       http://www.springframework.org/schema/util

       http://www.springframework.org/schema/util/spring-util-4.3.xsd

       http://www.springframework.org/schema/data/jpa

       http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd

       http://www.springframework.org/schema/context

       http://www.springframework.org/schema/context/spring-context-4.3.xsd"> 

          

      <bean id="cObj" class="beans.ComplexObject">

         <!-- String[]数组属性注入值 -->

         <property name="names">

             <list>

                <!-- #{}spring中的一个表达式 -->

                <value>name-1</value>

                <value>name-2</value>

             </list>

         </property>

         <!-- list<String>集合注入值 -->

         <property name="address">

             <list>

               <value>北京</value>

               <value>深圳</value>

               <value>上海</value>

             </list>

         </property>

         <!-- map属性注入值 -->

         <property name="map">

            <map>

               <entry key="k1" value="200"/>

               <entry key="k2" value="300"/>

            </map>

         </property>

         <!-- properties属性注入值 -->

         <property name="properties">

            <props>

              <prop key="pk1">pv1</prop>

              <prop key="pk2">pv2</prop>

            </props>

         </property>

         

      </bean>

</beans>

 

案例2spring配置文件中引入properties文件中的数据

 

step1:类路径的根目录定义properties文件cfg.properties,其内容如下:

 

driver=com.mysql.jdbc.Driver

url=jdbc:mysql:///test

username=root

password=root

 

step2:spring配置文件中引入此配置文件(借助util标签)

 

<util:properties 

          id="cfg" 

          location="classpath:cfg.properties"/>

 

step3:在Bean对象中引入配置文件中的值

 

     <bean id="dataSource" class="beans.DataSource">

          <property name="driver" value="#{cfg.driver}"/>

          <property name="url"  value="#{cfg.url}"/>

          <property name="username" value="#{cfg.username}"/>

          <property name="password" value="#{cfg.password}"/>

       </bean>

 

其中#{}spring中一个表达式,通过这个表达式可以获取properties文件中的值

例如#{cfg.driver}为获取idcfg对应的对象中keydriver的值。

 

2.0.3. 依赖值的自动装配

 

Spring中为bean对象中的属性提供了自动装配功能,此功能的开启需要借助bean标签中的autowire属性进行指定,此属性的值默认有如下几个:

 

1. 

NO 

自动配置(默认)

2. 

ByName

按名字自动装配(重点掌握)

3. 

ByType

按类型自动状态(重点掌握),但有多个类型时会出错

4. 

Constructor

byType类似,不同之处在于它应用于构造器参数。

 

例如:

定义并配置DataSource对象

 

public class DataSource {

}

 

 

<bean id="dataSource" class="beans.DataSource"/>

   

 

定义并配置JdbcTemplate对象

 

public class JdbcTemplate {

private DataSource dataSource;

public JdbcTemplate() {}

public JdbcTemplate(DataSource dataSource) {

this.dataSource=dataSource;

}

public void setDataSource(DataSource dataSource) {

this.dataSource = dataSource;

}

 

   <bean id="jdbcTemplate"

          class="beans.JdbcTemplate"

          autowire="constructor">

   </bean>

 

自动装配应用总结

 

v byName 按属性对应的set方法名从容器中查找名字相同的bean,然后进行注入。假如出现了名字相同,但类型不同的Bean对象时,会注入失败

v byType 先从容器中查找属性类型相匹配的值然后找按类中对应的set方法(看参数类型)最后通过set方法为对象的属性注入值。假如容器中出现多个类型相同的对象,就会注入失败。

v constructor 先从容器中查找属性类型相匹配的值然后找类中对应的构造方法(看参数类型)最后通过构造方法为对象的属性注入值。假如容器中出现多个类型相同的对象,此时再比对参数名字,假如有同名的则直接注入,没有同名的就会注入失败。

3. Spring 注解应用

3.1. Spring 注解概述

Spring中提供了两种方式对Bean进行描述,一种是基于xml方式,一种是基于注解方式。基于注解方式主要是依托于注解对bean以及bean中的属性进行描述

然后spring底层通过反射获取bean上定义的这些注解,通过注解描述初始化对象,管理对象的作用域以及对象与对象之间的依赖。

 

3.2. Spring 注解基本应用

 

3.2.1. 常用注解说明

组件应用注解

 

注解名

说明

1. 

@Component

通用注解

2. 

@Repository

持久层组件应用注解

3. 

@Service

业务层组件应用注解

4. 

@Controller

控制层组件应用注解

 

3.2.2. 注解应用案例

 

数据层对象

@Repository

public class SysUserDaoImpl implements SysUserDao{

public void saveUser(Object obj) {

System.out.println("dao.save.user");

}

}

 

业务层对象

@Service

public class SysUserServiceImpl implements SysUserService{

}

 

控制层对象

@Controller

public class UserController {

 

}

 

 

3.2.3. 配置注解扫描

 

Spring中通过指定一个包路径,由系统自动扫描该包及其子包所有组件类,当发现组件类定义前有特定的注解标记时,就将该组件纳入到Spring容器。

 

例如:

使用组件扫描,首先需要在XML配置中指定扫描父级package路径,例如

 

<context:component-scan

 base-package=”com.company.spring/>”

 

在这个配置中,容器会自动扫描org.example包及其子包下所有组件,并实例化bean对象。

 

3.2.4. 编写测试类获取bean

 

3.3. Spring 注解应用增强

 

3.3.1. 作用域及生命周期

 

@Scope("singleton")

@Repository

public class SysUserDao {

  /**@PostConstruct注解修饰方法在对象初始化时执行*/

  @PostConstruct

  public void init(){

System.out.println("init");  

  }

  public void insertObject(){

  System.out.println("insertObject");

  }

  /**@PreDestroy对象销毁时执行*/

  @PreDestroy

  public void destory(){

  System.out.println("destory");

  }

}

 

3.3.2. 延迟加载配置

 

@Lazy(false)

@Service

public class SysUserService {

}

 

3.3.3. 自动装配配置

 

注解方式的自动装配一般会借助@Autowired@Resource实现,

具体过程参考课堂案例,然后总结实践其过程(作业)。

 

注解自动装配使用说明:

应用位置

1@Autowired/@Qualifier 一般用于修饰属性和构造方法

2@Resource 一般用于修饰属性和set方法

 

注入规则:

1@Autowired 修饰属性,构造方法,set方法时默认按照属性类型

或参数类型进行值的注入。假如容器中有多个类型相同的Bean

此时还会按名字进行匹配,没有相匹配的则注入失败。假如希望

按名字进行匹配需要再此基础加上@Qualifier注解。

 

2@Resource 修饰属性,set方法时默认按属性名或set方法

名进行匹配,假如Resource指定了名称则按指定名称进行匹配,

假如没有找到相匹配的名称,则按类型进行值的注入。

 

4. Spring 注解工厂应用剖析

 

4.1. Bean工厂是用于做什么的?

 

所有的工厂都是用于创建对象的,对象创建一般会基于某中策略

对对象进行存储。

 

例如Spring 中的Bean工厂:ApplicationContext

1) ClassPathXmlApplicationContext

2) AnnotationApplicationContext

3) …….

 

4.2. Bean工厂的实现的基本原理?

 

Spring 中所有的Bean假如需要由Spring管理,此时需要以xml描述的方式或

注解的描述方式告诉spring容器。Spring底层内置了对xml的解析,通过反射

获取注解描述,然后基于这些描述通过反射构建对象。

4.3. Bean工厂理解的拔高?

手写基于注解方式的Spring Bean工厂

 

1) 包的扫描(将包转换为类所在的路径,然后进行文件的查找)

2) 构建类全名(包名+类名,例如java.util.Date

3) 基于反射构建类的对象(获取Class对象,构建构造方法对象,构建类的实例对象)

4) 存储类的对象(key是谁)

5) 需要时从工厂中获取bean对象即可

 

4.4. Bean 工厂手写应用实践

 

4.4.1. 注解定义实现

定义一个用于修饰bean,描述bean的注解。

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public @interface Component {     

String value() default "";

}

 

定义一个用于描述配置的注解

 

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public @interface ComponentScan {

  String value() default "";

}

 

 

4.4.2. 定义Bean组件

定义一个IdGenerator类,然后使用@Component注解修饰

 

@Component

public class IdGenerator {}

 

4.4.3. 定义Bean工厂

这个Bean工厂要实现的功能是基于配置类上的@ComponentScan注解,对注解中定义包进行类的扫描,然后构建类的对象,再将对象存储到map集合,需要时从map获取。其代码如下:

 

public class AnnotationAppContext{

private Map<String,Object> beanMap=

new HashMap<String,Object>();

public AnnotationAppContext(Class<?> c)throws Exception{

//1.获取class(例如AppConfig)上的@ComponentScan注解

ComponentScan cs=

    c.getAnnotation(ComponentScan.class);

//2.获取注解中定义的包名

String pkg=cs.value();

//替换包名中的“.”,改成目录结构

String dir=pkg.replaceAll("\\.", "/");

//3.基于包获取包对应的类路径

URL url=

getClass().getClassLoader()

.getResource(dir);

System.out.println("url="+url);

//4.获取类路径下所有的class文件(例如IdGenerator)

File pkgDir=new File(url.getPath());

//4.1获取目录下所有class文件

File[] fs=pkgDir.listFiles();//class

//4.2遍历所有文件,构建类全名

for(File f:fs){

String fname=

f.getName().substring(0,f.getName().lastIndexOf("."));

String clsName=pkg+"."+fname;

Class<?> cls=Class.forName(clsName);

//5.基于class文件上注解(@Component)描述构建类对象

if(!cls.isAnnotationPresent(Component.class))

continue;

Object obj=newInstance(cls);

//6.将类对象存储到map集合

//6.1获取key的值

Component cp=cls.getAnnotation(Component.class);

String key=cp.value();

if("".equals(key)){

key=String.valueOf(

fname.charAt(0)).toLowerCase()+

fname.substring(1);

}

//6.2存储到map

beanMap.put(key, obj);

}

}

private Object newInstance(Class<?> cls)

throws Exception{

Constructor<?> c=

cls.getDeclaredConstructor();

c.setAccessible(true);

return c.newInstance();

}

public Object getBean(String beanName){

return beanMap.get(beanName);

}

@SuppressWarnings("unchecked")

public <T>T getBean(String beanName,

Class<T> cls){

return (T) beanMap.get(beanName);

}

public static void main(String[] args)

throws Exception{

AnnotationAppContext ctx=

new AnnotationAppContext(AppConfig.class);

IdGenerator obj1=(IdGenerator)

ctx.getBean("idGenerator");

IdGenerator obj2=

ctx.getBean("idGenerator",IdGenerator.class);

System.out.println(obj1);

System.out.println(obj2==obj1);

}

}

 

 

5. 总结

5.1. 重点和难点分析

1. Spring 注解的强化理解

2. Spring 注解方式实现自动装配

3. Spring Bean工厂手写方式的实现。

 

5.2. 常见FAQ

4. URL是什么

5. URL的值什么情况下为空

6. 注解是什么,如何自己定义

7. 工厂应用中泛型方法如何实现

 

5.3. 作业

8. 总结spring注解应用

9. 尝试手写spring bean 工厂

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值