什么是Spring(面试):
Spring是一个分层的一站式的开源框架,可以将各个层集成在一起,提高开发效率,
Spring可以给我们解耦,比如平常我们要一个对象是要new一个对象,如果这个对象被成百上千次使用,那么突然有一天要换一个对象怎么办?成百上千个文件都要换?这个时候就体现出Spring的IOC的思想的好处,如果用了ioc思想就可以将想要的对象的全域名添加到
IOC思想: 也叫控制反转,由主动初始化到被动由工厂创建的这个过程就是控制反转 控制:对象的创建和销毁 反转:对象的控制权从开发者给了工厂,工厂+反色+配置文件
IOC代码思想的转变:
//需求:创建service层对象
UserServiceImpl userService = new UserServiceImpl();
// 存在的问题:耦合严重。 当service层类需要变动,左右两遍都要修改。
UserSerivce userService = new UserServiceImpl();
// 好处:解耦。 当dao层实现类需要变动,等号左边代码不需要修改。
// 缺点:等号右边代码还要变动。
ResourceBundle bundle = ResourceBundle.getBundle("service");//读取配置文件
String userServiceClassName = bundle.getString("userService");//获取配置文件中信息
Class userServiceCalss = Class.forName(userServiceClassName);//反射获取类的Class对象
UserService userService = (UserService) userServiceCalss.newInstance();//实例化
// 好处: 进一步解耦。 当service层实现类需要变动,不需要修改代码(直接修改配置文件即可)
// 缺点: 代码多。 (对程序员来讲)
UserService userService = (UserService) BeanFactory.getBean("userService");
// 好处: 封装了创建对象的方法,更好的管理对象。
那么他的配置文件*.XML文件是怎么加载的呢?
是使用Application接口的实现类ClassPathXmlApplication去解析xml
接下来是一个简单的通过工厂创建对象的案例:
//测试
@Test
public void test01() {
//通过ClassPathXmlApplicationContext来解析xml配置文件
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过给出配置文件的唯一标识符id的名称来获取对象
UserService userService = (UserService) cpxac.getBean("UserService");
userService.test();
}
//接口
public interface UserService {
void test();
}
//接口的实现类
public class UserServiceImpl implements UserService {
public void test() {
System.out.println("这是test,开始打印这句话.....");
}
}
他的xml文件为
Spring的bean标签:
在Spring中,默认是单例模式(饿汉模式):在加载配置文件的时候就会创建这个对象,并且是同一个对象。而懒汉模式是创建的时候会创建这个对象,并且不是同一个对象。
在SPring的
@Test
public void test01() {
//通过ClassPathXmlApplicationContext来解析xml配置文件
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//通过给出配置文件的唯一标识符id的名称来获取对象
UserService userService = (UserService) cpxac.getBean("UserService");
System.out.println("userService = " + userService);
UserService userService1 = (UserService) cpxac.getBean("UserService");
System.out.println("userService1 = " + userService1);
}
通过输出可以发现
userService = com.itheima.service.impl.UserServiceImpl@36b4cef0
userService1 = com.itheima.service.impl.UserServiceImpl@36b4cef0
他们的地址值是一个,说明他们是同一个对象,这是在xml默认的情况下,而且他是在加载的时候就创建了,也就是没有调用就已经随着xml文件加载被创建
将bean中用scope去改一下他的模式
scope有两个值:prototype懒汉 singleton:饿汉,或者不写默认就是singleton
输入结果是:
userService = com.itheima.service.impl.UserServiceImpl@7a187f14
userService1 = com.itheima.service.impl.UserServiceImpl@6f195bc3
地址值不一样的,而且用了他以后就是调用的时候才回去加载他的构造方法
Spring-IOC的生命周期:就是对象的创建到销毁的过程
单例对象:scope="singleton"
生命周期:
创建:当应用加载,创建容器的时候就被创建了
活着:容器在就一直活着
死亡:容器销毁了对象也就销毁了
多例对象:scope="prototype"
生命周期:
创建:当使用对象时创建
活着:对象使用就会活着
销毁: 对象长时间不用就会被java的gc销毁,所以他的销毁不归spring容器管
可以在bean标签中,使用init-method,destroy-method两个属性,分别定义bean对象在初始化或销毁时要完成的工作
是表示创建UserServiceImpl1对象的时候就会调用他里面的init(_方法,如果时单例的话,当容器销毁或者关闭了就会调用des()方法,他这个方法是自己定义调用的,前提是UserServiceImpl1里有这个方法。如果是多例的话创建的时候会调用init()方法,销毁的时候不会调用,因为多例销毁不归容器管
Spring的IOC配置-bean对象创建方式:
1):方式一:直接配置
2):方式二:静态工厂
3):方式三:实例工厂
直接配置就是之前通常的配置:
通过bean标签的配置,spring会利用反射来创建这个对象并装配到容器中,通过反射创建这个对象时是默认使用类的无参构造方法来实例化bean的
应用场景:在配置的时候,知道实现类的全限定名 (一般自己写bean)
底层原理:无参构造 (要求类中必须有无参构造方法)
缺点:开发者需要知道类名
方式二:静态工厂
步骤:先写一个静态工厂类,然后里面有一个静态方法,通过静态方法去得到这个对象
public class UserServiceFactory {
public static UserServiceImpl getBean(){
return new UserServiceImpl();
}
}
方式三:实例工厂:
使用实例工厂的形式创建bean
public class InstanceFactory {
//非静态方法
public UserService getBean() {
UserService userService = new UserServiceImpl2();
return userService;
}
}
依赖注入:使用Spring的容器可以降低耦合,但是不能完全消除依赖,比如一个类中有一个参数是一个自定义类型,然后想要给他赋值还要通过工厂创建对象然后去接收。注入就可以实现不去接收也可以在创建这个对象的时候去给他赋值
使用前的代码:
//业务层
public class UserServiceImpl3 implements UserService {
//dao层对象
private UserDao userDao;//成员变量
//无参构造方法
public UserServiceImpl3(){
//1.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取Spring容器中的资源
userDao = (UserDao) ctx.getBean("userDao");//仅仅只是让Spring创建bean对象,降低了依赖关系。 但还是需要自己书写代码接收Spring创建的bean对象。
}
public void save(User user) {
//调用dao层对象中的添加用户方法
userDao.save(user);
}
}
常用的注入有两种方式给成员变量赋值:
1:setter方法、 2:构造方法
1:setter方法:
public class UserServiceImpl3 implements UserService {
private int num; //基本类型
private String name; //String类型
private UserDao userDao; //dao层对象
private Date birthday; //Date类型
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
}
这是上边修改的实现类,必须要写构造方法
2:构造器注入:
public class UserServiceImpl3 implements UserService {
private int num; //基本类型
private String name; //String类型
private UserDao userDao; //dao层对象
private Date birthday; //Date类型
//有参构造方法
public UserServiceImpl3(int num , String name, UserDao userDao, Date date){
this.num = num;
this.name = name;
this.userDao= userDao;
this.birthday = date;
}
//无参构造方法
public UserServiceImpl3(){
}
public void save(User user) {
System.out.println("成员变量 num:"+num);
System.out.println("成员变量 name:"+name);
System.out.println("成员变量 birthday:"+birthday);
//调用dao层对象中的添加用户方法
userDao.save(user);
}
}
集合类型的注入:
原理:
clazz = Class.forName("com.itheima.service.impl.UserServiceImpl5")
service = clazz.newInstance();
setList = service.getMethod("setList",List.class);
List list = new ArrayList();
list.add("zs");
list.add("ls");
list.add("ww");
setList.invoke(service,list);// service.setList(list)
-->
元素
元素
value元素
元素值
Spring的IOC的EL表达式:
就是数据引用,在配置mybatis的时候就有#{} ${} 这两个符号,而${}这个是可以读取properties文件的值,比如 username=root 就可以通过在xml中写${username}得到他的值,他在bean中的用法就是:
使用properties文件的值,这里用${}
先准备context命名空间支持:
xmlns:context="http://www.springframework.org/schema/context"
加载指定的properties 文件
接下来就能使用里面的值了:



