Spring-- 快速入门,rabbitmq 面试题总结
运行结果:
从结果中可以看出,我们并没有使用 new 的方式实例化对象,但是我们的对象已经被实例化了。
Bean是Spring容器初始化、装配和管理的对象,它是由 spring 来创建的,默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
标签的属性:<bean>
id: 给对象在容器中提供一个唯一标识。用于获取对象。
class: 指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope: 指定对象的作用范围。
singleton :默认值,单例的.
prototype :多例的.
request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么 globalSession 相当于 session
init-method: 指定类中的初始化方法名称。
destroy-method: 指定类中销毁方法名称。
创建 Bean 的三种方式
项目结构:
第一种方式:根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其它属性和标签时,采用的就是默认函数创建bean对象,此时如果类中没有默认构造函数则对象无法创建。
<bean id="accountService" class="com.ly.service.impl.AccountServiceImpl"></bean>
第二种方式:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
/**
@Author: Ly
@Date: 2020-07-23 23:27
模拟一个工厂类(该类可能是存在于 jar 包中的,我们无法通过修改源码的方式来提供默认构造函数)
*/
public class InstanceFactory {
public IAccountService getAccountService(){
return new AccountServiceImpl();
}
}
<bean id="instanceFactory" class="com.ly.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
第三种方法:使用工厂中的静态方法创建对象(使用某个静态方法创建对象,并存入spring容器)
/**
@Author: Ly
@Date: 2020-07-23 23:27
模拟一个工厂类(该类可能是存在于 jar 包中的,我们无法通过修改源码的方式来提供默认构造函数)
*/
public class StaticFactory {
public static IAccountService getAccountService(){
return new AccountServiceImpl();
}
}
<bean id="accountService" class="com.ly.factory.StaticFactory" factory-method="getAccountService"></bean>
bean 的作用范围和生命周期:
<?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">
<!--bean 对象的生命周期
单例对象:scope="singleton"
一个应用只有一个对象的实例,它的作用范围就是整个引用
出生:当容器创建时出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
多例对象:scope="prototype"
每次访问对象时,都会重新创建对象实例
出生: 当我们使用对象时 spring 框架为我们创建
活着: 对象只要在使用过程中就一直活着
死亡: 当对象长时间不用,且没有别的对象引用时,由 Java 的垃圾回收器回收
-->
<bean id="accountService" class="com.ly.service.impl.AccountServiceImpl"
scope="prototype" init-method="init" destroy-method="destroy"></bean>
</beans>
依赖注入:Dependency Injection, 它是 spring 框架核心 IOC 的具体实现。
我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。我么知道 IOC 的作用是降低程序间的耦合,而不是消除耦合。对于我们项目中业务层和持久层的依赖关系,我们可以交给 spring 来维护,在我们的类中需要用到其他类的对象时,可以由由 spring 为我们提供。通过 spring 框架把持久层对象传入到业务层,从而省去我们自己获取的步骤。
依赖注入可以注入三种类型的数据:基本类型和string、其他bean类型(在配置文件中或者注解配置过的bean)、复杂类型/集合类型
同时有三种注入方式:构造函数提供、set方式提供、注解提供
案例:
构造函数注入:
通过使用类中的构造函数,给成员变量赋值。在这之中,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。具体代码如下:
/**
@Author: Ly
@Date: 2020-07-21 16:31
账户的业务成实现类
*/
public class AccountServiceImpl implements IAccountService {
//如果是经常变化的数据,并不适用于注入的方式
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name,Integer age,Date birthday){
this.name=name;
this.age=age;
this.birthday=birthday;
}
public void saveAccount() {
System.out.println("service 中的 saveAccount 方法执行了,"+name+","+age+","+birthday);
}
}
<!--构造函数注入
使用的标签:constructor-arg
标签出现的位置,bean 标签的内部
标签的属性
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数类型
index:用于指定要注入的数据结构函数中指定索引位置的参数赋值。索引的位置是从 0 开始
name:用于指定构造函数中指定名称的参数赋值
===========以上三个用于指定给构造函数中哪个参数赋值=========
value:用于给基本类型和 String 类型的数据
ref:用于指定其他的 bean 类型数据。它指的就是在 spring 的 Ioc 核心容器中出现过的容器
优势:
在获取 bean 对象时,注入数据是必须的操作,否则对象无法创建成功
弊端:
改变了 bean 对象的实例化方式,是我们在创建对象时,如果用不到这些数据也必须提供
-->
<bean id="accountService" class="com.ly.service.impl.AccountServiceImpl">
<constructor-arg type="java.lang.String" name="name" value="test"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>
set 方法注入
在类中提供需要注入成员的 set 方法,进行注入。具体代码如下:
/**
@Author: Ly
@Date: 2020-07-21 16:31
账户的业务成实现类
*/
public class AccountServiceImpl2 implements IAccountService {
//如果是经常变化的数据,并不适用于注入的方式
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void saveAccount() {
System.out.println("service 中的 saveAccount 方法执行了,"+name+","+age+","+birthday);
}
}
<!--set 方法注入
涉及的标签:property
出现的位置:bean 标签的内部
标签的属性
name:用于指定注入时所调用的 set 方法名称,与变量名称无关
value:用于提供基本类型和 String 类型的数据
ref:用于指定其他的 bean 类型数据,它指的就是在 spring 的 Ioc 核心容器中出现过的容器
优势:
创建对象时没有明确的限制,可以直接使用默认构造函数
弊端:
如果某个成员必须有值,则 set 方法无法保证一定注入
-->
<bean id="accountService2" class="com.ly.service.impl.AccountServiceImpl2">
<property name="name" value="test"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
复杂类型注入:
依赖注入可以注入复杂的数据类型,如 s 数组、集合,同时注入这些复杂数据也是 set 方法注入的方式,只不过变量的数据类型都是集合。具体代码如下:
/**
@Author: Ly
@Date: 2020-07-21 16:31
账户的业务成实现类
*/
public class AccountServiceImpl3 implements IAccountService {
private String[] myStrs;
private List<String> myList;
private Set<String> mySets;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySets(Set<String> mySets) {
this.mySets = mySets;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySets);
System.out.println(myMap);
System.out.println(myProps);
}
}
<bean id="accountService3" class="com.ly.service.impl.AccountServiceImpl3">
<!-- 在注入集合数据时,只要结构相同,标签可以互换。
如 list、array、set 可以互换,map、set、properties 可以互换 -->
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="mySets">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB" >
<value>BBB</value>
</entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="testA">ccc</prop>
<prop key="testB">ddd</prop>
<
/props>
</property>
</bean>
自 Spring2.5 开始,允许使用注解(Annotation)来代替 XML 格式的配置文件,从而简化 spring 应用开发,极大的缩减了 Spring 配置文件的代码配置量。
Spring 中的常用注解有以下几种:
用于创建对象的注解
创建对象的注解的作用就和 XML 配置文件中编写一个标签实现的功能是一样的,用于把当前类对象存入 spring 容器中,包括@Component、@Constroller、@Service、@Repository
,这四个注解在作用和属性上是一摸一样的,都具有 value 属性:用于指定 bean 的 id,当我们不写时,它的默认值是当前类名(首字母小写)。通常情况下我们会使用 @Component 来标注一个普通的 Spring Bean, 而 @Constroller,@Service,@Repository 三个注解分别对应我们三层架构的表现层、业务层、持久层,使我们的三层架构更加清晰。
用于注入数据的注解
注入数据的注解的作用就和在 xml 配置文件中的 bean 标签中写一个<property>
标签实现的功能是一样的,用来注入数据,在使用注解注入时,我们会发现 set 方法已经不是必须的了。
@Autowired:自动按照类型注入。只要容器中有唯一的一个 bean 对象类型和要注入的变量类型匹配,就可以注入成功,注意:如果ioc容器中没有任何bean类型和要注入的变量类型匹配或者有多个类型匹配时报错。
@Qualifier:在按照类中注入的基础之上再按照名称注入。他们在给类成员注入时不能单独使用但是在给方法参数注入时可以。
@Resource:直接按照 bean 的 id 注入,可以独立使用。
@Value:用于注入基本类型和 String 类型的数据。属性:value:用于指定数据的值,它可以使用 spring 中 SpEl(也就是 Spring 中的 el 表达式),SpEl 的写法:${表达式}
@Autowired、@Qualifier、@Resource 三个注解都只能注入其他 bean 类型的数据,而基本类型和 String 类型要使用 @Value 注解实现,集合类型的注入只能通过 XML 实现。
用于改变作用范围的注解
改变作用范围的注解的作用就和 bean 标签中使用 scope 属性实现的功能是一样的,@Scope:用于指定 bean 作用范围,属性:value:指定范围的取值。常用取值:singleton prototype
生命周期相关的注解
@PreDestroy:用于指定销毁方法
@PostConstruct:用于指定初始化方法
它们的作用就和在 bean 标签中使用 init-method 和 destroy-method 的作用是一样的
案例:基于注解的 IOC 开发
项目结构:
在进行基于注解的 IOC 开发时,首先我们应该对 bean.xml 进行相应配置,用来告知 spring 在创建容器时要扫描的包
<?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">
<!--告知 spring 在创建容器时要扫描的包,配置所需要的标签不是在 beans 的约束中,
而是在 context 名称空间的约束中-->
<context:component-scan base-package="com.ly"></context:component-scan>
</beans>
创建对象的注解
创建账户的持久层实现类和接口:
/**
账户的持久层实现类
*/
@Repository("accountDao1")
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("保存了账户");
}
}
/**
@Author: Ly
@Date: 2020-07-21 16:33
账户的持久层接口
*/
public interface IAccountDao {
/**
模拟保护账户
*/
void saveAccount();
}
创建账户的业务层实现类和接口:
/**
@Author: Ly
@Date: 2020-07-21 16:31
账户的业务成实现类
*/
//在此处添加创建对象的注解,value 属性:用于指定 bean 的 id,当我们不写时,它的默认值是当前类名。
//@Component(value = "accountService")
@Service(value = "accountService")
//@Scope("protoype") //改变作用范围
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
/*测试生命周期相关的注解
@PostConstruct
public void init(){
System.out.println("初始化方法执行了");
}
@PreDestroy
public void destroy(){
System.out.println("销毁方法执行了");
}*/
public AccountServiceImpl(){
System.out.println("对象创建了");
}
public void saveAccount() {
accountDao.saveAccount();
}
评论