常见的设计模式
单例模式
单例模式是保障了程序运行期间,一个类只能有一个对象(实例)的代码开发模块
使用场景:工具类(一种做法,所有的方法都是static,还有一种单例模式让工具类只有一个实例), 某类工厂(SqlSessionFactory)
以下为三种实现方式:
饿汉模式(迫切加载)
实现方式
public class Singleton {
//构造方法私有化保证自己才能创建
public Singleton() {
}
//创建一个private对象
private static final Singleton INSTANCE = new Singleton();
//提供一个方法来获取这个单例对象
public static Singleton getInstance(){
return INSTANCE;
}
}
调用方法查看是否是调用的同一个对象
Singleton instance = Singleton.getInstance();
Singleton instance02 = Singleton.getInstance();
System.out.println(instance02);
System.out.println(instance);
调用两个方法的地址值相同,可以看出调用的同一个对象
懒汉模式(懒加载)
饿汉模式的方法不管用不用都会创建,占用资源,懒汉模式只在需要的时候再创建
实现方式
以下为多线程容易出现问题的
//构造方法私有化保证自己才能创建
public Singleton02() {
}
//创建一个private对象
private static Singleton02 INSTANCE =null;
//提供一个公有方法来获取这个单例对象
public static Singleton02 getInstance(){
//如果为null就是没有创建过,进if创建
//多线程容易出问题的位置
if (INSTANCE==null){
INSTANCE=new Singleton02();
}
//如果创建过,直接返回INSTANCE
return INSTANCE;
}
修改后:双重校验加同步锁
//构造方法私有化保证自己才能创建
public Singleton02() {
System.out.println(Thread.currentThread().getName());
}
//创建一个private对象
private static Singleton02 INSTANCE =null;
//提供一个公有方法来获取这个单例对象
public static Singleton02 getInstance(){
if (INSTANCE==null){
//加代码块锁防止多线程问题
synchronized (Singleton02.class){
//如果为null就是没有创建过,进if创建
if (INSTANCE==null){
INSTANCE=new Singleton02();
}
}
}
//如果创建过,直接返回INSTANCE
return INSTANCE;
}
测试方法:
for (int i = 0; i < 10; i++) {
new Thread(() -> {
Singleton02.getInstance();
}).start();
}
枚举
工厂模式
对象工厂使用别人的包,如果别人改名字,会影响到自己代码的运行,可以使用映射并用配置文件进行解耦
public class ObjectFactory {
/**
* 对象工厂,传入对象字节码就能创建一个对象
*/
public static Object getObj(String key) throws Exception{
Properties properties = new Properties();
properties.load(ObjectFactory.class.getClassLoader().getResourceAsStream("factory.properties"));
String value = properties.getProperty("key");
Object o = Class.forName(value).newInstance();
return o;
}
}
配置文件factory.properties:
factory.date=java.util.Date//如果别人改包名,只要把java.util.Date改了就行
Spring
概念
Spring是一个开源的轻量级控制反转(IOC:将对象交给框架管理)和面向切面编程(AOP)的容器框架; Spring是Bean的容器,Bean就是对象,之前都是自己new对象,而有了Spring框架就不用new,直接用就行
导包&配置
需要哪个模块自己下载
完成第一个Spring
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
准备Spring配置文件
- 在resources下新建一个
applicationContext.xml配置文件
<?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">
</beans>
将类交给Spring容器中
- 准备一个普通的类
public class Hello {
public void test(){
System.out.println("hello.Spring");
}
}
- 将它交到Spring容器,
在
applicationContext.xml里配置
<!--配置bean,将类交给spring容器管理,表示对象配置
id属性: bean的唯一标识
class属性: 类的全限定名-->
<bean id="hello" class="com.lifei._03Spring.Hello"></bean>
注意:Spring容器中不允许有两个名字【不管是id指定还是name指定】一个的对象
Spring容器的实例化
Spring容器对象有两种:BeanFactory和ApplicationCOntext
BeanFactory
- BeanFactory是一个接口,可以通过其实现类XmlBeanFactory获取其实例。
//读取配置文件
ClassPathResource resource = new ClassPathResource("applicationContext.xml");
//拿到BeanFactory接口
XmlBeanFactory factory = new XmlBeanFactory(resource);
//从工厂中获取Bean
Hello hello = (Hello) factory.getBean("hello");
//调用
hello.test();
//以下为调用另外两种方式
Hello hello1 = factory.getBean(Hello.class);
hello1.test();
Hello hello2 = factory.getBean("hello", Hello.class);
hello2.test();
执行以上代码,可以调到Hello类里的方法:
ApplicationCOntext(常用)
//加载工程classpath下的配置文件实例化
ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = factory.getBean("hello", Hello.class);
hello.test();
ApplicationCOntext和`BeanFactory的区别
- ApplicationCOntext是
继承于BeanFactory - ApplicationCOntext是
迫切加载(默认是在读取配置文件的时候就会根据配置创建Bean对象),BeanFactory是懒加载(在使用的时候才进行对象的创建)
让ApplicationCOntext也成为懒加载
- 配置一:让所有Bean都变成懒加载,只需要在标签中加入
default-lazy-init="true":
- 配置二:让其中一个Bean变成懒加载,在标签中加入
**lazy-init="true"**:
Spring管理Bean的两种方法
- 先创建两个类(DaoBean和ServiceBean)
- 在ServiceBean类里用DaoBean里的方法
public class DaoBean {
public void testDaoBean(){
System.out.println("我是dao");
}
}
public class ServiceBean {
private DaoBean daoBean;
public void testServiceBean(){
System.out.println("我是Service");
daoBean.testDaoBean();
}
}
Spring依赖注入
- Ioc的一个重点是在系统运行中,动态的向某个对象提供它所需要的对象,这一点是通过
DI(Dependency Injection,依赖注入)来实现的
xml注入
在xml中进行配置,但这种方法必须要有对应的set和get方法,也被称为属性注入和setter方法注入
bean定义
public class ServiceBean {
//set和get方法
public DaoBean getDaoBean() {
return daoBean;
}
public void setDaoBean(DaoBean daoBean) {
this.daoBean = daoBean;
}
private DaoBean daoBean;
public void testServiceBean(){
System.out.println("我是Service");
daoBean.testDaoBean();
}
}
xml配置:
测试:
ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
ServiceBean serviceBean = factory.getBean("serviceBean", ServiceBean.class);
serviceBean.testServiceBean();
注解注入
- 需要在核心配置文件里面用约束开启注解扫描
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
"
>
-
加注解
@Controller , @Service , @Repository(往持久层打,dao/mapper), @component(往工具类或者公共类打)
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.lifei._05annotation"></context:component-scan>
测试注解
- 在上面的两个类中测试(注解扫描就是刚刚配的那个),在DaoBean上面打
@Repository
- ServiceBean类上打
@Service,而要获取DaoBean类的数据,还需要在属性上打@Autowired注解或者@Resource注解
测试类同上
@Autowired和@Resource区别:
@Autowired:先根据类型查找,如果找到多个,再根据名字查找
@Resource: 先根据名字查找,如果找到多个,再根据类型查找
Spring测试
第一步:导包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
第二步:编写注解和方法
注解
- @RunWith:表示先启动Spring容器,把junit运行在Spring容器中
- @ContextConfiguration("classpath:applilcationContext.xml"):表示从classpath路径去加载配置文件
- @Autowired:表示自动装配,自动从Spring容器中取出对应Bean复制给当前使用的属性
Spring测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest02 {
@Autowired
private ApplicationContext factory;
@Autowired(取代下面那行代码)
private ServiceBean serviceBean;
@Test
public void test01(){
// ServiceBean serviceBean = factory.getBean("serviceBean", ServiceBean.class);
serviceBean.testServiceBean();
}
}
配置细节
作用域
Spring默认是单例
代码证明:
ServiceBean serviceBean = factory.getBean("serviceBean", ServiceBean.class);
ServiceBean serviceBean02 = factory.getBean("serviceBean", ServiceBean.class);
System.out.println(serviceBean==serviceBean02);
通过xml的Bean元素中的scope属性指定
- singleton:默认值,单例
- prototype:多例
<bean id="daoBean" class="com.lifei._04di.DaoBean" scope="prototype"></bean>
通过注解配置
在类上方打注解@Scope("prototype") 或着@Scope("singleton")
其他属性值(一般都不用)
Bean对象的生命周期
- 生命周期值得是:从对象创建、初始化、调用执行到销毁的一个过程
- 不同作用域的Bean,生命周期有所区别:
1、 Spring管理的Bean对象默认是单例,生命周期会从创建到结束
2、多例的生命周期是:创建 -> 初始化 -> 工作 ,没有销毁
Bean类的创建和初始化:
public class MyBean {
public MyBean() {
System.out.println("对象创建");
}
public void init(){
System.out.println("对象初始化");
}
public void work(){
System.out.println("对象工作");
} public void destroy(){
System.out.println("G了");
}
}
配置文件:
<bean id="myBean" class="com.lifei._03Spring.MyBean" init-method="init" destroy-method="destroy"></bean>
注解版本:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyTest02 {
@Autowired
private MyBean myBean;
@Test
public void test(){
myBean.work();
}
}
结果: