使用spring框架建立一个项目
1.建立一个maven项目,在pom中加入Spring的框架的依赖。
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies>
2.使用xml来配置你所需要的bean对象,下文给的例子放在了显示层来创建bean对象
3.xml配置了,显示层来创建bean对象的方法也有两种,如图
IAccountService as = (IAccountService)ac.getBean("accountService"); IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);
<?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"> <!--把对象的创建交给spring来管理,就是这里配置的--> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean> </beans>
package com.itheima.dao.impl; import com.itheima.dao.IAccountDao; /** * 账户的持久层实现类 */ public class AccountDaoImpl implements IAccountDao { public void saveAccount(){ System.out.println("保存了账户"); } }
package com.itheima.dao; /** * 账户的持久层接口 */ public interface IAccountDao { /** * 模拟保存账户 */ void saveAccount(); }
package com.itheima.service.impl; import com.itheima.dao.IAccountDao; import com.itheima.service.IAccountService; /** * 账户的业务层实现类 */ public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao ;//这里我们原来是private IAccountDao accountDao=new AccountDaoImpl();因为我们完成了工厂模式,进行了xml的《bean》的注解public AccountServiceImpl(){ System.out.println("对象创建了"); } public void saveAccount(){ accountDao.saveAccount(); } }
package com.itheima.service; /** * 账户业务层的接口 */ public interface IAccountService { /** * 模拟保存账户 */ void saveAccount(); }
package com.itheima.ui; import com.itheima.dao.IAccountDao; import com.itheima.service.IAccountService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 模拟一个表现层,用于调用业务层 */ public class Client { /** * 获取spring的Ioc核心容器,并根据id获取对象 * * ApplicationContext的三个常用实现类: * ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用) * FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限) * * AnnotationConfigApplicationContext:它是用于读取注解创建容器的,是明天的内容。 * * 核心容器的两个接口引发出的问题: * ApplicationContext: 单例对象适用 采用此接口 * 它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。 * * BeanFactory: 多例对象使用 * 它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。 * @param args */ public static void main(String[] args) { //1.获取核心容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); // ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\zhy\\Desktop\\bean.xml"); //2.根据id获取Bean对象 IAccountService as = (IAccountService)ac.getBean("accountService"); IAccountDao adao = ac.getBean("accountDao",IAccountDao.class); System.out.println(as); System.out.println(adao); as.saveAccount(); //--------BeanFactory---------- // Resource resource = new ClassPathResource("bean.xml"); // BeanFactory factory = new XmlBeanFactory(resource); // IAccountService as = (IAccountService)factory.getBean("accountService"); // System.out.println(as); } }
问题:spring提供了几种工厂呢?
两种:1.上述的applicationContext
2.使用Beanfactory
他们什么区别?
一个适合单例模式,一个适合多例模式
问题:xml是配置了,你怎么找到你的xml呢?
一、三种找到你xml的方法
高大上一点就是Application的三种实现类
一、通俗说就是使用 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
二、通俗说就是使用 ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\zhy\\Desktop\\bean.xml");
//也就是你磁盘上的xml的真实路径,你查查在你磁盘哪里
三、就是使用注解的方法 在方法上加@xxxxx这种
问题:你的xml也找到了,如何在xml中配置bean呢?也就是文艺的叫做三种创建bean的方法
tip:第一种用于你写的bean类
第二种用于jar包中bean类,你想使用jar包的,你不可能找到它的工厂,所以我们使用工厂的方法,即factory-bean
第三种和第二种一样,都是jar包中的,这种特殊在是static关键字修饰的类,但是使用方法同第二种
id属性: 指定对象在容器中的标识,用于从容器中获取对象
class属性: 指定静态工厂的全类名
factory-method属性: 指定生产对象的静态方法
问题:bean既然配置了,它的使用范围有多大呢?
这个是bean上的《Scope》属性
解释一下:
1.单例,默认,就是你创建的bean是单例模式,只会创建一个对象来处理我们所有的请求,比如Dao和Service
2.多例,就是你创建的bean是多例模式,在使用bean时会创建很多对象来处理我们的请求
3.request,请求,就是你向服务器请求,要求服务器为你干啥的时候有用
4.session,就是你俩已经建立了关系,你俩商量,我要啥,服务器说我要啥,咱俩沟通沟通
5.集群,就是大型网络供应商,服务器有很多台,他们都处理客户端的请求,因为有很多人访问,这时候中间会加一个东西,叫负载均衡来帮助分发请求。
问题,你bean创建完了,什么时候销毁呢?
别忘了,容器就是你第一句先获取的AplicationContext对象
问题:你先在一个个的bean做好了,他们之间的关系怎么交给Spring呢?
也就是依赖注入
顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置 的方式,让 spring 框架来为我们注入。具体代码如下: /**
适用场景,不经常变的数据,如用户姓名,性别等,
缺点,只要是配置的属性,就比如传入,比如你在网页上使用这种方法,用户就必须填写用户名。 */ 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; } @Override public void saveAccount() { System.out.println(name+","+age+","+birthday); } } <!-- 使用构造函数的方式,给 service 中的属性传值 要求: 类中需要提供一个对应参数列表的构造函数。 涉及的标签: constructor-arg 属性: index:指定参数在构造函数参数列表的索引位置 type:指定参数在构造函数中的数据类型 name:指定参数在构造函数中的名称 用这个找给谁赋值
=======上面三个都是找给谁赋值,下面两个指的是赋什么值的==============
value:它能赋的值是基本数据类型和 String 类型 ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="张三"></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>
2.set方法
顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:另外对于复杂类来说,相同类型复杂类,可以互换
/** */ public class AccountServiceImpl implements IAccountService { private String name;//小写 private Integer age; private Date birthday; public void setName(String name) {//大写,可以使用快捷键1.光标在类里面,按alt+insert。弹出一个小窗,可以用它生成多种代码。 2.点击getter与setter这个 3.现在弹出一个小窗,让你选择给哪个生成set和get方法
this.name = name; } public void setAge(Integer age) { this.age = age; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public void saveAccount() { System.out.println(name+","+age+","+birthday); } } <!-- 通过配置文件给 bean 中的属性传值:使用 set 方法的方式 涉及的标签: property 属性: name:找的是类中 set 方法后面的部分 ref:给属性赋值是其他 bean 类型的 value:给属性赋值是基本数据类型和 string 类型的 实际开发中,此种方式用的较多。 -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="name" value="test"></property> //小写
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property> </bean>
<bean id="now" class="java.util.Date"></bean>
3.使用注解的方法
你说上述这种bean文件太麻烦了,有没有简单的。答案是有
怎么做?查阅官方文档,找到注解的xml的写法
1.xml中的文件改成,请和原来的xml进行比较,basepackage就是你所希望写类的包的路径
<?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="cn.maoritian"></context:component-scan> </beans>
2.在类的开始加上注解@component
3.常用注解
用于创建对象的注解
这些注解的作用相当于bean.xml中的<bean>标签
@Component: 把当前类对象存入spring容器中,其属性如下:
value: 用于指定当前类的id. 不写时默认值是当前类名,且首字母改小写
@Controller: 将当前表现层对象存入spring容器中
@Service: 将当前业务层对象存入spring容器中
@Repository: 将当前持久层对象存入spring容器中
这三个的注解的作用和属性与
@Component
是一模一样的,可以相互替代,它们的作用是使三层对象的分别更加清晰.
问题:我们已经通过@component等注解告诉ioc容器有这几个bean,如何使用注解进行数据注入呢?
Service肯定需要Dao层,因为要拿出数据。
上述我们使用的时set构造函数进行的注入,我们想使用注解
就需要@autowired注解进行数据注入,也就是在变量对象上加上注解。
问题:它是如何进行注入的呢?
Dao接口会去找实现类进行注入。如果有DaoImpl1和DaoImpl2两个实现类,该找哪个?就会报错了。所以也就是Dao只能有唯一一个实现类!
问题:现在我就是有两个实现类,他们有不同的功能,你怎么处理?
先回忆一下。@Component(“变量名”)这个注解没忘记把,
那就使用@qualifier注解进行指定,它不能单独使用,必须指定@Component后跟的变量名,并且配合@Autowired使用
这他麻烦了,我不想记。你就可以使用@resource注解,使用方法如下
@resource(name=“bean名字”)
问题:如何确定bean的使用范围
使用@Scope,放在类的头上就是对整个类有用,放在方法上,就是对方法有用
总结:
问题:如何替代xml中的配置呢?
在使用xml配置中,我们是用
<context:component-scan base-package="cn.maoritian"></context:component-scan>
我们现在不在xml中配置了,我们建一个config类。充当xml的角色。
使用注解
@configuration代表这是一个配置类
@component-scan来代表应该去哪里找bean
问题:@Bean是干什么的呢?
导入junit的依赖
这里的@Autowired注解,没有用。注入不进去,使用@RunWith,表示junit把原有的方法替换了。
问题:如何在config.class这个配置类中动态的配置jdbc链接
描述:我们希望改的时候只改jdbc的链接和密码,而不动代码
我们可以设置一个变量来存储,然后使用properties文件存储我们的用户名和密码
这样下次需要改动的时候我们只需要改动properties文件即可,实现了解耦
那么我们如何将properties和我们的config.class联系,
就是在congfig类加个注解
@propertySource(properties的路径)
这个properties的文件一般新建在resource中,也就是properties相对于resource的路径