文章目录
Spring学习记录:
DI入门案例:
- 基于IoC管理bean
- service中使用new创建的Dao对象是否可以保留(否)
- service中需要Dao对象该如何添加到service中(提供方法)
- Service与Dao之间的关系如何描述(配置文件)
applicationContext.xml:
<bean id="bookDao" class="org.wgq.dao.impl.BookDaoImpl"/>
<!-- Dao传入到Service 所以需要在Service中配置-->
<bean id="bookService" class="org.wgq.service.impl.BookServiceImpl">
<!-- 配置Serviece与Dao的关系-->
<!-- name中的bookDao是BookServiceImpl中的私有对象 ref中指的当前容器中为bookDao的bean-->
<!-- property标签表示配置属性-->
<!-- name属性表示配置哪一个的具体属性-->
<!-- ref属性表示参照哪一个bean-->
<property name="bookDao" ref="bookDao"/>
</bean>
public class BookServiceImpl implements BookService{
//删除业务层中使用new创建的对象
// private BookDao bookDao=new BookDaoImpl();
private BookDao bookDao;
@Override
public void Save() {
System.out.println("BookService Save");
bookDao.Save();//调用BookDao中的Save();
}
//提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
最主要的目的降低耦合度
Bean配置:
bean基础配置:
Bean别名:
使用name 可以设置多个名称,使用别名的话那么在拿到bean对象时便可以使用别名。
可以使用逗号(,)分号(;)空格( )分隔。
也可以使用别名定义reference:
bean的作用范围:
public class AppForScope
{
public static void main( String[] args )
{
ApplicationContext context=new ClassPathXmlApplicationContext("applicatinContext.xml");
BookDao bookDao =(BookDao)context.getBean("bookDao");
System.out.println(bookDao);
BookDao bookDao1 =(BookDao)context.getBean("bookDao");
System.out.println(bookDao1);
}
}
显然地址时一致的,所以可以得出Spring为我们创建bean时是单例模式。
若要创建非单例怎么做?(修改配置)
使用Scope属性,prototype(非单例模式)singleton(单例模式)。
为什么bean默认为单例模式?
**答:**Spring管理我们的对象时为了提高效率,同时为服务器减压采用单例(若需要调用Dao中的一次方法便创建一个Bean则Bean会无穷无尽)。
那么Bean的控制范围实际上是Spring为了控制创建Bean的数量。
Bean的实例化:
什么是Bean,bean是如何创建出来的:
bean本质上就是对象,创建bean使用无参构造方法完成(常用)
<!-- 方式1构造方法实例化bean-->
<bean id="bookDao" class="org.wgq.dao.impl.BookDaoImpl" scope="singleton"/>
Bean的三种实例化方式:
通过静态工厂创建(早期常用方法):
造对象不要自己new,而是使用工厂,达到一定程度的解耦。
<!-- 方式2 使用静态工厂创建bean-->
<bean id="orderDao" class="org.wgq.factory.OrderDaoFactory" factory-method="getOrderDao"/>
<!-- factory-method 属性表示调用工厂中的某一实例化bean的方法-->
package org.wgq;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.wgq.factory.OrderDaoFactory;
public class AppForInstanceOrder {
public static void main(String[] args) {
// OrderDao orderDao=OrderDaoFactory.getOrderDao();
// orderDao.Save();
ApplicationContext context=new ClassPathXmlApplicationContext("applicatinContext.xml");
OrderDao orderDao = (OrderDao) context.getBean("orderDao");
orderDao.Save();
}
}
-
package org.wgq.dao.impl; import org.wgq.OrderDao; public class OrderDaoImpl implements OrderDao { @Override public void Save() { System.out.println("OrderDao Save() Is Running!!!"); } }
-
package org.wgq.factory; import org.wgq.OrderDao; import org.wgq.dao.impl.OrderDaoImpl; public class OrderDaoFactory { public static OrderDao getOrderDao(){ return new OrderDaoImpl(); } }
-
package org.wgq; public interface OrderDao { void Save(); }
实例工厂实例化Bean:
与静态的区别在于工厂的get方法没有static。
package org.wgq.factory;
import org.wgq.UserDao;
import org.wgq.dao.impl.UserDaoImpl;
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
package org.wgq;
import org.wgq.factory.UserDaoFactory;
public class AppForInstanceUser {
public static void main(String[] args) {
//需要先通过工厂的实例对象调用get方法,返回给userDao
//不可以直接通过工厂完成实例化
UserDaoFactory userDaoFactory =new UserDaoFactory();
UserDao userDao=userDaoFactory.getUserDao();
//工厂返回后,再调用user实现类中的方法
userDao.Save();
}
}
<!-- 1. 先造工厂Bean-->
<bean id="userFactory" class="org.wgq.factory.UserDaoFactory"/>
<!-- 2. 使用工厂Bean对象创建user-->
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
package org.wgq;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.wgq.factory.UserDaoFactory;
public class AppForInstanceUser {
public static void main(String[] args) {
// UserDaoFactory userDaoFactory =new UserDaoFactory();
// UserDao userDao=userDaoFactory.getUserDao();
// userDao.Save();
ApplicationContext ctx =new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.Save();
}
}
FactoryBean(掌握):
class定义对象的具体属性。通过FactoryBean完成对象实例化。
在FactoryBean中添加方法,返回为true则为单例(默认不加方法也为单例)
false为非单例。
Bean的生命周期:
主调用方法:
package org.wgq;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AppforLifecycle {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.Save();
}
}
BookDao实现类:
package org.wgq.dao.impl;
import org.wgq.BookDao;
public class BookDaoImpl implements BookDao {
// public BookDaoImpl() {
// System.out.println("BookDao constructor is running===");
// }
public void Save(){
System.out.println("BookDao Save");
}
//初始化Bean
public void init(){
System.out.println("init bean...");
}
//销毁bean
public void destroy(){
System.out.println("destroy bean...");
}
}
运行结果:
初始化方法即销毁方法均未调用。为什么呢?是因为我们并未在配置文件中进行配置。
配置:
<bean id="bookDao" class="org.wgq.dao.impl.BookDaoImpl" scope="singleton" init-method="init" destroy-method="destroy"/>
<!-- init-method 初始化方法 destrot-method 销毁方法-->
运行结果:
我们发现初始化方法已经调用了,那销毁方法呢?
解答:是因为我们的程序目前跑在java虚拟机中,Vm拿到IoC容器后并初始化bean,然后获取对象,再调用Save()方法,那么程序结束,虚拟机直接退并没有给机会使其销毁Bean。
所以需要以下方法销毁
两种方式销毁Bean:
调用Close()方法:
我们会发现它并没有close的方法可以调用。我们需要换一个接口。
这样close方法就有了。
运行结果:
关闭注册钩子:
意思是在虚拟机关闭前,先关闭我的容器
任何位置都可,即也可以放在Save()前后都行。
运行结果:
两者的区别:
Close相比之下更加暴力,且close的执行时间必须在容器执行完需要做的事情后才能关闭容器。
若Close在获取对象之前等,如下:
则会报错!
使用Spring接口关闭:
继承接口:
生成方法:
配置文件:
去掉我们自己实现的方法。
运行结果:
afterPeopertiesSet()表示在属性设置完后再初始化。