写点什么

Spring-- 快速入门,rabbitmq 面试题总结

用户头像
极客good
关注
发布于: 刚刚

运行结果:



从结果中可以看出,我们并没有使用 new 的方式实例化对象,但是我们的对象已经被实例化了。


实例化 Bean 对象




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>


<


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


/props>


</property>


</bean>


基于注解的 IOC 配置




自 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();


}

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Spring--快速入门,rabbitmq面试题总结