Spring超详细的快速入门教程(一)

全文目录:

  1. Spring概述
  2. IOC理论推导
  3. 快速上手Spring
  4. 依赖注入(DI)
  5. 自动装配

1. Spring概述

1.1 简介

1.2 优点

一句话概括:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

1.3 组成


1.4 拓展

2. IOC理论推导

2.1 IoC基础

分析实现,我们先用我们原来的方式写一段代码 :

1、先写一个UserDao接口

public interface UserDao {
 public void getUser();
}

2、再去写Dao的实现类

public class UserDaoImpl implements UserDao {
 @Override
 public void getUser() {
 System.out.println("获取用户数据");
 }

3、然后去写UserService的接口

public interface UserService {
 public void getUser();
}

4、最后写Service的实现类

public class UserServiceImpl implements UserService {
 private UserDao userDao = new UserDaoImpl();

 @Override
 public void getUser() {
 userDao.getUser();
 }
}

5、测试一下

@Test
public void test(){
 UserService service = new UserServiceImpl();
 service.getUser();
}

这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下

把Userdao的实现类增加一个

public class UserDaoMySqlImpl implements UserDao {
 @Override
 public void getUser() {
 System.out.println("MySql获取用户数据");
 }
}

紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现

public class UserServiceImpl implements UserService {
 private UserDao userDao = new UserDaoMySqlImpl();

 @Override
 public void getUser() {
 userDao.getUser();
 }
}

在假设, 我们再增加一个Userdao的实现类 .

public class UserDaoOracleImpl implements UserDao {
 @Override
 public void getUser() {
 System.out.println("Oracle获取用户数据");
 }
}

那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .

那我们如何去解决呢 ?

我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下

public class UserServiceImpl implements UserService {
 private UserDao userDao;
 // 利用set实现
 public void setUserDao(UserDao userDao) {
 this.userDao = userDao;
 }

 @Override
 public void getUser() {
 userDao.getUser();
 }
}

现在去我们的测试类里 , 进行测试 ;

@Test
public void test(){
 UserServiceImpl service = new UserServiceImpl();
 service.setUserDao( new UserDaoMySqlImpl() );
 service.getUser();
 //那我们现在又想用Oracle去实现呢
 service.setUserDao( new UserDaoOracleImpl() );
 service.getUser();
}

大家发现了区别没有 ? 可能很多人说没啥区别 . 但是同学们 , 他们已经发生了根本性的变化 , 很多地方都不一样了 . 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

2.2 IOC本质

3. 快速上手Spring

3.1 HelloSpring

(1)导入Jar包

注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 .


 org.springframework
 spring-webmvc
 5.1.10.RELEASE

(2)编写代码

1、编写一个Hello实体类

public class Hello {
 private String name;

 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }

 public void show(){
 System.out.println("Hello,"+ name );
 }
}

2、编写我们的spring文件 , 这里我们命名为beans.xml

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


 
 
 
 

3、我们可以去进行测试了 .

@Test
public void test(){
 //解析beans.xml文件 , 生成管理相应的Bean对象
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 //getBean : 参数即为spring配置文件中bean的id .
 Hello hello = (Hello) context.getBean("hello");
 hello.show();
}

修改案例一

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


 
 

 
 
 
 
 

@Test
public void test2(){
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
 serviceImpl.getUser();
}

3.2 IOC创建对象方式

通过无参构造方法来创建

1、User.java

public class User {

 private String name;

 public User() {
 System.out.println("user无参构造方法");
 }

 public void setName(String name) {
 this.name = name;
 }

 public void show(){
 System.out.println("name="+ name );
 }

}

2、beans.xml

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


 
 
 

3、测试类

@Test
public void test(){
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 //在执行getBean的时候, user已经创建好了 , 通过无参构造
 User user = (User) context.getBean("user");
 //调用对象的方法 .
 user.show();
}

结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!

通过有参构造方法来创建

1、UserT . java

public class UserT {

 private String name;

 public UserT(String name) {
 this.name = name;
 }

 public void setName(String name) {
 this.name = name;
 }

 public void show(){
 System.out.println("name="+ name );
 }

}

2、beans.xml 有三种方式编写



 
 



 
 



 

3、测试

@Test
public void testT(){
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 UserT user = (UserT) context.getBean("userT");
 user.show();
}

结论:在配置文件加载的时候。其中管理的对象都已经初始化了!

3.3 Spring配置

(1)别名

alias 设置别名 , 为bean设置别名 , 可以设置多个别名


(2)Bean的配置





 

(3)import

团队的合作通过import来实现 .

4. 依赖注入(DI)

4.1 概念

4.2 构造器注入

我们在之前的案例已经讲过了

4.3 Set 注入

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .

测试pojo类 :

Address.java

 public class Address {
 
     private String address;
 
     public String getAddress() {
         return address;
    }
 
     public void setAddress(String address) {
         this.address = address;
    }
 }

Student.java

 package com.kuang.pojo;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 public class Student {
 
     private String name;
     private Address address;
     private String[] books;
     private List hobbys;
     private Map card;
     private Set games;
     private String wife;
     private Properties info;
 
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAddress(Address address) {
         this.address = address;
    }
 
     public void setBooks(String[] books) {
         this.books = books;
    }
 
     public void setHobbys(List hobbys) {
         this.hobbys = hobbys;
    }
 
     public void setCard(Map card) {
         this.card = card;
    }
 
     public void setGames(Set games) {
         this.games = games;
    }
 
     public void setWife(String wife) {
         this.wife = wife;
    }
 
     public void setInfo(Properties info) {
         this.info = info;
    }
 
     public void show(){
         System.out.println("name="+ name
                 + ",address="+ address.getAddress()
                 + ",books="
        );
         for (String book:books){
             System.out.print("<<"+book+">>	");
        }
         System.out.println("
爱好:"+hobbys);
 
         System.out.println("card:"+card);
 
         System.out.println("games:"+games);
 
         System.out.println("wife:"+wife);
 
         System.out.println("info:"+info);
 
    }
 }

4.3.1 常量注入

 
     
 

测试:

 @Test
 public void test01(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 
     Student student = (Student) context.getBean("student");
 
     System.out.println(student.getName());
 
 }

4.3.2 Bean注入

注意点:这里的值是一个引用,ref

 
     
 
 
 
     
     
 

4.3.3 数组注入

 
     
     
     
         
             西游记
             红楼梦
             水浒传
         
     
 

4.4.4 List注入

 
     
         听歌
         看电影
         爬山
     
 

4.4.5 Map注入

 
     
         
         
     
 

4.4.6 set注入

 
     
         LOL
         BOB
         COC
     
 

4.4.7 Null注入

 

4.4.8 Properties注入

 
     
         20190604
         
         小明
     
 

测试结果:

4.4 p命名和c命名注入

User.java :【注意:这里没有有参构造器!】

 public class User {
     private String name;
     private int age;
 
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAge(int age) {
         this.age = age;
    }
 
     @Override
     public String toString() {
         return "User{" +
                 "name='" + name + ''' +
                 ", age=" + age +
                 '}';
    }
 }

4.1 P命名空间注入

需要在头文件中加入约束文件

 导入约束 : xmlns:p="http://www.springframework.org/schema/p"
 
 
 

4.2 c 命名空间注入

需要在头文件中加入约束文件

导入约束 : xmlns:c="http://www.springframework.org/schema/c"
 
 

发现问题:爆红了,刚才我们没有写有参构造!

解决:把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!

测试代码:

 @Test
 public void test02(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     System.out.println(user);
 }

4.5 Bean的作用域

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .

几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。

4.5.1 Singleton

当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

 

测试:

 @Test
 public void test03(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     User user2 = (User) context.getBean("user");
     System.out.println(user==user2);
 }

4.5.2 Prototype

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

   
  或者
 

4.5.3 Request

当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

 

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

4.5.4 Session

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

 

针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉

5. 自动装配

5.1 Bean的自动装配

推荐不使用自动装配xml配置 , 而使用注解

测试环境搭建

1、新建一个项目

2、新建两个实体类,Cat Dog 都有一个叫的方法

public class Cat {
 public void shout() {
 System.out.println("miao~");
 }
}public class Dog {
 public void shout() {
 System.out.println("wang~");
 }
}

3、新建一个用户类 User

public class User {
 private Cat cat;
 private Dog dog;
 private String str;
}

4、编写Spring配置文件

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


 
 

 
 
 
 
 

5、测试

public class MyTest {
 @Test
 public void testMethodAutowire() {
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 User user = (User) context.getBean("user");
 user.getCat().shout();
 user.getDog().shout();
 }
}

结果正常输出,环境OK

5.1.1 byName

autowire byName (按名称自动装配)

由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。

采用自动装配将避免这些错误,并且使配置简单化。

测试:

1、修改bean配置,增加一个属性 autowire="byName"


   

2、再次测试,结果依旧成功输出!

3、我们将 cat 的bean id修改为 catXXX

4、再次测试, 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。

小结:

当一个bean节点带有 autowire byName的属性时。

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
  2. 去spring容器中寻找是否有此字符串名称id的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常。

5.1.2 byType

autowire byType (按类型自动装配)

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

NoUniqueBeanDefinitionException

测试:

1、将user的bean配置修改一下 : autowire="byType"

2、测试,正常输出

3、在注册一个cat 的bean对象!






   

4、测试,报错:NoUniqueBeanDefinitionException

5、删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

这就是按照类型自动装配!

5.2 使用注解

jdk1.5开始支持注解,spring2.5开始全面支持注解。
准备工作:利用注解的方式注入属性。

1、在spring配置文件中引入context文件头

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

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd2、开启属性注解支持!

2、开启属性注解支持!

@Autowired

测试:
1、将User类中的set方法去掉,使用@Autowired注解

public class User {
   @Autowired
   private Cat cat;
   @Autowired
   private Dog dog;
   private String str;

   public Cat getCat() {
       return cat;
  }
   public Dog getDog() {
       return dog;
  }
   public String getStr() {
       return str;
  }
}

2、此时配置文件内容





3、测试,成功输出结果!
@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。

//如果允许对象为null,设置required = false,默认为true
@Autowired(required = false)
private Cat cat;

@Qualifier

测试实验步骤:
1、配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!




2、没有加Qualifier测试,直接报错
3、在属性上添加Qualifier注解

@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

测试,成功输出!

@Resource

实体类:

public class User {
    //如果允许对象为null,设置required = false,默认为true
    @Resource(name = "cat2")
    private Cat cat;
    @Resource
    private Dog dog;
    private String str;
}

beans.xml





测试:结果OK
配置文件2:beans.xml , 删掉cat2


实体类上只保留注解

@Resource
private Cat cat;
@Resource
private Dog dog;

结果:OK
结论:先进行byName查找,失败;再进行byType查找,成功。

5.3 小结

@Autowired与@Resource异同:

1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用

3、@Resource(属于J2EE规范),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

展开阅读全文

页面更新:2024-05-28

标签:注解   容器   框架   实例   属性   入门教程   定义   对象   作用   快速   方式   测试   详细

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top