Spring

1.Spring定义

Spring 是一个开源框架,Spring 是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson在其著作 Expert One-On-One J2EE Development and Design 中阐述的部分理念和原型衍生而来。

它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE应用程序开发提供集成的框架。Spring 使用基本的 JavaBean 来完成以前只可能由 EJB 完成的事情。然而,Spring 的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 的核心是控制反转(IOC)和面向切面(AOP)。简单来说,Spring 是一个分层的 轻量级开源框架。

2.为什么使用Spring

  1. 方便解耦,简化开发
  2. Spring 就是一个大工厂,可以将所有对象创建和依赖关系维护,交给 Spring 管理
  3. AOP 编程的支持,Spring 提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  4. 声明式事务的支持只需要通过配置就可以完成对事务的管理,
  5. 而无需手动编程方便程序的测试,Spring 对 Junit4 支持,可以通过注解方便的测试 Spring 程序
  6. 方便集成各种优秀框架,Spring  不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz 等)的直接支持
  7. 降低 JavaEE API 的使用难度,Spring 对 JavaEE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等),都提供了封装,使这些 API 应用难度大大降低

3.Spring环境搭建

3.1 创建Spring项目,并引入相关依赖

3.1.1项目创建

3.1.2 引入spring的依赖

 <properties>

        <maven.compiler.source>8</maven.compiler.source>

        <maven.compiler.target>8</maven.compiler.target>

        <spring.version>4.2.5.RELEASE</spring.version>

    </properties>  

                         <!--Spring核心基础依赖-->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-core</artifactId>

            <version>${spring.version}</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>${spring.version}</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-beans</artifactId>

            <version>${spring.version}</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-expression</artifactId>

            <version>${spring.version}</version>

        </dependency>

        <!--日志相关-->

        <dependency>

            <groupId>commons-logging</groupId>

            <artifactId>commons-logging</artifactId>

            <version>1.2</version>

        </dependency>

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>1.2.17</version>

        </dependency>

        <!--测试相关-->

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.12</version>

            <scope>test</scope>

        </dependency>

3.2添加配置文件

配置文件的名字可以任意设置,建议设置为applicationContext.xml

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

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

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

       xsi:schemaLocation="http://www.springframework.org/schema/beans

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

</beans>

3.3 添加相应的模块

在项目中添加dao、model、service层代码

3.4将bean的实例化交给Spring

<bean name="userDao" class="com.tledu.spring.dao.impl.UserDaoImpl" />

<!--name 属性名字/ref 引用的bean的名字-->

<bean id="userService" class="com.tledu.spring.service.UserService">

        <property name="userDao"  ref="userDao" />

</bean>

4.通过构造方法注入

 <bean name="userDao" class="com.tledu.spring.dao.impl.UserDaoImpl" />

    <bean id="userService" class="com.tledu.spring.service.UserService">

        <constructor-arg ref="userDao"/>

    </bean>

5.普通属性注入

<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">

        <!-- 如果不是指向对象,直接用value设置值就行 -->

                 <property name="daoId" value="82"></property>

                 <property name="daoStatus" value="good"></property>

        </bean>

 6.scope

spring中scope是一个非常关键的概念,简单说就是对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式。

目前,scope的取值有5种取值:

在Spring 2.0之前,有singleton和prototype两种;

在Spring 2.0之后,为支持web应用的ApplicationContext,增强另外三种:request,session和global session类型,它们只实用于web程序,通常是和XmlWebApplicationContext共同使用

6.1singleton

此取值时表明容器中创建时只存在一个实例,所有引用此bean都是单一实例。

也就是说创建对象是单例模式,并且如果不进行设置,默认就行单例

6.2prototype

每次获取都创建一个新对象,并且这个对象的生命周期不归Spring管理

6.3配置scope方式

<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">

  <!-- 如果不是指向对象,直接用value设置值就行 -->

  <property name="daoId" value="82"></property>

  <property name="daoStatus" value="good"></property>

        </bean >

        <!-- scope singleton : 单例 只创建一个,默认就是

                 prototype : 每一次getBean 都会创建一个新的实例化对象 

  request,session : 需要特殊环境支持 -->

        <bean id="userService" class="com.tledu.zrz.service.UserService"

  scope="singleton">

  <!-- 构造方法注入 -->

  <constructor-arg>

         <ref bean="userDao" />

  </constructor-arg>

</bean>

 7.集合属性注入

7.1相关类

UserDaoImpl中提供对应的变量

private List<String> lists;

        private Set<String> sets;

        private Map<String, String> maps;

        public List<String> getLists() {

                 return lists;

        }

        public void setLists(List<String> lists) {

                 this.lists = lists;

        }

        public Set<String> getSets() {

                  return sets;

        }

        public void setSets(Set<String> sets) {

                  this.sets = sets;

        }

        public Map<String, String> getMaps() {

                  return maps;

        }

        public void setMaps(Map<String, String> maps) {

                  this.maps = maps;

        }

7.2配置文件

<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">

  <property name="lists" >

         <list>

         <value>1</value>

         <value>2</value>

         </list>

  </property>

  <property name="sets" >

  <!-- set不可重复,重复不添加,所以只有第一个三 -->

         <set>

         <value>3</value>

         <value>3</value>

         <value>5</value>

         <value>4</value>

         </set>

  </property>

  <property name="maps">

  <!-- mapkey不可重复,重复key不添加,value覆盖 -->

         <map>

         <entry key="1"  value="2"></entry>

         <entry key="1"  value="3"></entry>

         <entry key="2"  value="2"></entry>

         </map>

  </property>

        </bean>

        <bean id="userService" class="com.tledu.zrz.service.UserService"

  scope="singleton">

  <!-- 构造方法注入 -->

  <constructor-arg>

         <ref bean="userDao" />

  </constructor-arg>

        </bean>

8.自动装配

上面我们进行对象注入的时候有两种方式

1 set方法注入

<property name="userDao" ref="userDao" />

2 构造方法注入

<constructor-arg>

    <ref bean="userDao"/>

</constructor-arg>

现在我们来学习自动注入,就是不需要指定以上两种方式

Autowire : 自动装配,两种取值

1 byName

2 byType  

8.1byName

byName是根据setter方法名字进行匹配,如果找不到,就不赋值

如 setUserDao 方法  就会找userDao,如果 bean的ID为 UserDao 也一样找不到,区分大小写

设置方式

<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">

</bean>

<bean id="userService" class="com.tledu.zrz.service.UserService"  

 autowire="byName">

</bean>

8.2byType

byType是根据setter方法的参数列表中的数据类型进行匹配,如果beans.xml中出现了多个相同类型的对象,就会报错

如 setUserDao(UserDao userDao) 方法  就会找UserDao,如果是接口,就找对应的实现类对象

设置方式

<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">

</bean>

<bean id="userService" class="com.tledu.zrz.service.UserService"  

 autowire="byType">

</bean>

注意 : 使用自动装配,需要有公共的无参构造,虽然这里就算是私有化构造方法也依然可以创建对象,但是还是提供一个公共的比较好,万一别的框架需要呢

9.生命周期和迟加载

之前servlet的生命周期

构造方法 -- init -- service -- destroy  

那么spring创建对象的生命周期呢?

Spring中是没有init、service和destroy的,但是我们可以指定某个方法在创建完对象之后执行,某个方法在最后销毁的时候执行

9.1生命周期

9.1.1相关类

UserService中提供对应的方法

public void init(){

  System.out.println("init--------");

        }

        public void destroy(){

  System.out.println("destroy----------");

        }

        public UserService() {

  System.out.println("service构造方法");

}  

9.1.2配置文件

<bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl" >

        </bean>

        <!-- 

  init-method : 用于设置初始化的方法

  destory-method : 用于设置销毁资源的方法

  -->

        <bean id="userService" class="com.tledu.zrz.service.UserService" 

  autowire="byName"   init-method="init" destroy-method="destroy"  >

    </bean>

9.2迟加载

Spring容器默认是在执行

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");

进行解析的时候创建对象并调用init,

如果我们不想让某个类在解析的时候就创建对象,而是用到的时候在创建对象的话,就需要设置迟加载

比如想要对userService迟加载可以这样设置

9.2.1相关类

在UserDaoImpl和UserService中的构造方法添加输出语句进行测试

public UserDaoImpl(){

  System.out.println("Dao构造方法");

}

public UserService() {

  System.out.println("service构造方法");

}

9.2.2配置文件

 <bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl" >

<bean id="userService" class="com.tledu.zrz.service.UserService"  scope="prototype"

         autowire="byName"   init-method="init" destroy-method="destroy" lazy-init="true"  >

</bean>

为了使用方便,Spring还提出了default-lazy-init="true"

比如我们通过xml创建了10个对象,这10个对象都需要迟加载,那么每个bean标签中都设置lazr-init是比较麻烦的

于是我们可以在beans标签中添加default-lazy-init="true" 对所有的bean进行迟加载  

default-lazy-init 和 lazy-init 可以同时存在,比如 10个对象中 只有一个不需要迟加载,那么可以使用 default-lazy-init = true 全部设置迟加载,然后再去指定的bean中添加 lazy-init=false 就可以

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

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

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

        xsi:schemaLocation="http://www.springframework.org/schema/beans

       http://www.springframework.org/schema/beans/spring-beans.xsd"  default-lazy-init="true" >

10.IOC注解

10.1 XML和注解的区别

10.1.1 XML配置

优点有:

  1. XML配置方式进一步降低了耦合,使得应用更加容易扩展,即使对配置文件进一步修改也不需要工程进行修改和重新编译。
  2. 在处理大的业务量的时候,用XML配置应该更加好一些。因为XML更加清晰的表明了各个对象之间的关系,各个业务类之间的调用。同时spring的相关配置也能一目了然。  

缺点有:

配置文件读取和解析需要花费一定的时间,配置文件过多的时候难以管理,无法对配置的正确性进行校验,增加了测试难度。

10.1.2annotation配置

优点有:  

  1. 在class文件中,可以降低维护成本,annotation的配置机制很明显简单  
  2. 不需要第三方的解析工具,利用java反射技术就可以完成任务  
  3. 编辑期可以验证正确性,查错变得容易  
  4. 提高开发效率  

缺点有:  

  1. 如果需要对于annotation进行修改,那么要重新编译整个工程  
  2. 业务类之间的关系不如XML配置那样容易把握。  
  3. 如果在程序中annotation比较多,直接影响代码质量,对于代码的简洁度有一定的影响

10.2注解注入使用步骤

10.2.1Autowired

10.2.1.1导包

<dependency>

  <groupId>org.springframework</groupId>

  <artifactId>spring-aop</artifactId>

        <version>${spring.version}</version>

</dependency>

10.2.1.2 开启注解的支持

<?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 />

        <context:component-scan base-package="需要扫描的包名"/>

</beans>

10.2.1.3业务类

//类名上添加Component注解

@Component

public class UserService {

    private IUserDao userDao;

//需要注入的变量上添加@Autowired

    @Autowired

    public void setUserDao(IUserDao userDao) {

        this.userDao = userDao;

}

}

//获取bean时需要类名小驼峰

application.getBean("addressServiceImpl")

10.2.1.4知识点

@Autowired(自动封装)

该注解可以加在set方法上或者直接加载属性上,如果写在setter方法上,就会通过setter方法进行注入,如果写在变量上,就直接通过反射设置变量的值,不经过setter方法。

注入时,会从spring容器中,找到一个和这个属性数据类型匹配的实例化对象注入进来,默认使用byType,根据类型匹配。

如果只能找到一个这个数据类型的对象的时候,就直接注入该对象。

如果找到了多个同一个类型的对象的时候,就会自动更改为byName来进行匹配,根据set方法对应的参数列表的局部变量名来匹配。

@Qualifier :  

以指定名字进行匹配  

private IUserDao userDao;

@Autowired

public void setUserDao(@Qualifier(“userDao2”)IUserDao userDao){};

这时候就不会按照userDao来进行匹配了,而是强制使用userDao2来进行比配,也就不会按照类型匹配了

10.2.1.5配置文件

<?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 />

        <bean name="userDao" class="com.tledu.zrz.dao.impl.UserDaoImpl">

  <property name="daoId" value="1"></property>

        </bean>

  <bean name="userDao2" class="com.tledu.zrz.dao.impl.UserDaoImpl">

  <property name="daoId" value="2"></property>

        </bean>

        <bean id="userService" class="com.tledu.zrz.service.UserService">

        </bean>

</beans>

10.2.2Resource

Resource这个注解是javaEE的,在javax包下,所以不需要导入其他jar包

@Resource默认使用byName的方式,按照名字匹配,可以写在setter方法上也可以写在变量上

先匹配set方法的名字,匹配不上再匹配方法参数列表的名字

如果还是匹配不上就会转换为byType,根据类型匹配

当然我们也可以指定名字

@Resource(name=”userDao”)  

就相当于 Autowired和Qualifier 一起使用

相关的还有一个 @Inject 根据type匹配,通过named指定名字,自行学习  

导包javax.inject.Inject

10.2.2.1业务类

@Resource(name="userDao")

  public void setUserDao(UserDao userDao) {

         System.out.println("--------------");

         this.userDao2 = userDao;

        }

10.3注解实例化使用步骤

10.3.1配置文件

<?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 />

        <!-- 使用注解形式实例化对象 -->

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

</beans>

10.3.2业务类

所有需要实例化对象的类上面都加上@Component  

默认是以类名首字母小写作为名字进行存储

可以使用@Component(“xxx”) 或者@Component(value=”xxx”)来设置名字

@Component(value="userDao")

public class UserDaoImpl implements UserDao {

@Component

public class User {

@Component("userService")

public class UserService {

10.3.3 注解分类

@Controller :WEB 层 ,就是和页面交互的类

@Service :业务层 ,主要处理逻辑

@Repository :持久层 ,就是Dao操作数据库

这三个注解是为了让标注类本身的用途清晰,Spring 在后续版本会对其增强  

@Component: 最普通的组件,可以被注入到spring容器进行管理

@Value :用于注入普通类型. 可以写在变量上和setter方法上

@Autowired :自动装配,上面描述比较详细,可以参照上面

@Qualifier:强制使用名称注入.  

@Resource 相当于: @Autowired 和@Qualifier 一起使用

@Scope: 设置对象在spring容器中的生命周期

取值 :  

singleton:单例  

prototype:多例

@PostConstruct :相当于 init-method  

@PreDestroy :相当于 destroy-method  

10.3.4注解的区别

@Component 最普通的组件,可以被注入到spring容器进行管理

@Repository 作用于持久层

@Service 作用于业务逻辑层

@Controller 作用于表现层(spring-mvc的注解)

10.4新注解

10.4.1Configuration

作用: 用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration 注解的类.class)。

属性: value:用于指定配置类的字节码

package com.tledu.zrz.config;

import org.springframework.context.annotation.Configuration;

@Configuration

public class SpringConfiguration {

}

10.4.2ComponentScan

作用: 用于指定 spring 在初始化容器时要扫描的包。

作用和在 spring 的 xml 配置文件中的: <context:component-scan base-package="com.tledu.zrz.spring"/>是一样的。

属性: basePackages:用于指定要扫描的包。和该注解中的 value 属性作用一样。

@Configuration

@ComponentScan("com.tledu.zrz.spring")

public class SpringConfiguration {

}

10.4.3 Bean

作用: 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。

属性: name:给当前@Bean 注解方法创建的对象指定一个名称(即 bean 的 id)。

10.4.4 PropertySource

作用: 用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。

属性: value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath

package com.tledu.zrz.config;

import org.apache.commons.dbcp2.BasicDataSource;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

public class JdbcConfig {

        @Value("${jdbc.driver}")

        private String driver;

        @Value("${jdbc.url}")

        private String url;

        @Value("${jdbc.username}")

        private String username;

        @Value("${jdbc.password}")

        private String password;

}

10.4.5  Import

作用: 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问题。

属性: value[]:用于指定其他配置类的字节码。

@Configuration

@ComponentScan("com.tledu.zrz.spring")

@Import({ JdbcConfig.class})

public class SpringConfiguration {

}

// jdbc的配置

@Configuration

@PropertySource("classpath:jdbc.properties")

public class JdbcConfig {}

10.4.6  通过注解获取容器

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值