本文主要是介绍week15_day02_Spring_IOCDIApplicationContextlombokxml文件中注册bean的方式生命周期,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
总结昨天的内容:
-
设计模式
最佳实践(经验) -
特点
s:单一职责
o:开闭原则
l:里氏替代原则
i:接口隔离
d:依赖倒置 -
具体的设计模式
3.1单例(重要)
应用程序对应的实例只有一个
1、构造方法私有
2、包含自己的成员变量
3、提供静态方法给其他人调用
线程不安全的懒加载(在方法上开始初始化的)
线程安全的懒加载(在方法上开始初始化的,并且在方法上加锁sync)
线程安全的立即加载(在静态成员变量上直接初始化)
线程安全的立即加载(在静态代码块中初始化)
线程安全的懒加载(静态内部类实现,当你调用到静态内部类的方法的时候,静态内部类才加载) → 将实例初始化的过程放在了静态内部类中
3.2工厂
3.2.1简单工厂
给工厂方法的形参中 给不同的值,生产出的实例有所不同
当需要新的生产实例的时候,需要去修改工厂的生产方法
3.2.2工厂方法
更好的满足了开闭原则
提供一个工厂接口,提供生产方法的规范
具体的工厂实现工厂接口,在具体的工厂中提供详细的生产方法
3.2.3使用方式
3.2.3.1实例工厂
工厂中的生产方法非静态方法
先对工厂进行实例化,然后通过工厂对象来调用生产方法
3.2.3.2静态工厂
工厂中的方法是静态方法,可以直接调用。静态工厂类似于工具类。
3.3代理(非常重要)
给委托类实现原有的功能的基础上,并且进行增强
3.3.1静态代理
3.3.1.1委托类成员变量
委托类以代理类中的成员变量的形式存在,可以调用委托类对象的方法
在HouseProxy中定义了一个HouseOwner的成员变量
3.3.1.2代理类继承委托类
重写父类(委托类)的方法,并且在重写的方法中调用父类的方法(super来调用)
3.3.2动态代理
都是要获得一个代理对象,通过代理对象调用的方法才是增强的方法
3.3.2.1jdk动态代理
类要有接口的实现,生成的代理对象和接口相关。并且要用接口来接收。
HelloService helloService = new HelloServiceImpl();
Object proxy = Proxy.newProxyInstance(classloader,interfaces,new InvocationHandler(){public Object invoke(proxy,method,args){//前面的增强Object object = method.invoke(helloSerivce,args);//后面的增强return object;
}
});
Object proxy只能用接口来接收,不能用实现类。
3.3.2.2cglib动态代理
invocationHandler和jdk动态代理的invocationHandler是不同包下的,不是同一个
Object proxy = Enhancer.create(class,new InvocationHandler(){public Object invoke(proxy,method,args){//前面的增强Object object = method.invoke(helloSerivce,args);//后面的增强return object;
}
});
Object proxy可以用接口也可以用实现类来接收。
因为cglib的实现是用代理类继承委托类。根据里氏替换原则,可以用父类接收子类。
3.4建造者builder
更侧重于设置参数的过程
在builder中 在创建builder时(生产之前)已经完成了实例化
需要保证始终对同一个实例设置参数,实例就要求是全局变量
set方法如果想要连续用起来,要求这些set方法的返回值为builder
.setHeadIq(120).setHeadEq(120).setLegLength()
Spring介绍(4天)
SpringIOC
SpringAOP
Spring事务
Spring 概念
Spring框架其实就是偏基础性的框架。可以去整合其他框架。类似于平台。
核心:IOC、DI和AOP
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。
它是为了解决企业应用开发(JavaEE)的复杂性而创建的。框架的主要优势之一就是其分层架构(MVC分层),分层架构允许使用者选择使用哪一个组件,同时为 J2EE(JavaEE) 应用程序开发提供集成的框架。
Spring是一个分层的Java SE/EE full-stack(一站式) 轻量级开源框架。
IOC&DI
IOC用于实例化类对象,管理类对象
IOC:Inverse of Controll 控制反转
控制:实例的生成权
反转:由应用程序反转给spring
容器:容器是放置实例对象的地方 → Spring容器、IOC容器
原先实例我们想用的时候自己new出来(主动的过程);到了Spring阶段,把实例的生成权交给了Spring容器,由Spring容器进行生成并管理,当我们想用的时候就从容器中取出来。
例子:小明挣了10块钱自己花。
小明找到了对象,挣的10块钱交给了对象。小明想花5毛,就要跟对象申请。
所谓IOC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。
所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
DI:Dependency Injection 依赖注入
应用程序(贫穷) ←→ Spring容器(富有)
经过了控制反转,谁富有谁贫穷
依赖:
谁依赖谁? 小张依赖他对象 → 应用程序依赖Spring容器
为什么依赖? 小张对象有钱 → Spring容器包含了应用程序必须的内容
注入:
谁注入谁? Spring容器注入给应用程序
注入了什么?应用程序运行所必须的资源
谁依赖了谁:应用程序依赖于IOC容器
为什么要依赖:应用程序需要IOC容器来提供对象需要的外部资源
谁注入谁:IOC容器注入应用程序某个对象,应用程序依赖的对象
注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)
aop:面向切面编程→ aspect oriented programming
oop→ object oriented programming
Spring Introduction
声明式事务支持:指定方法增加事务 → 通过注解指定方法 → 指哪儿打哪儿
事务 → 保证使用的是同一个connection → aop阶段会布置对应的作业
Spring的单元测试 → 提供了Spring环境
Spring 特点:
Core technologies: dependency injection, events, resources, i18n, validation, data binding, type conversion, SpEL, AOP.
依赖注入、资源、i18n国际化(springmvc)、校验(Springmvc)、数据绑定、类型转换(springmvc)、SpringExpressionLanguage、Aop(面向切面编程)
Spring Framework:
Core Container是Spring的核心组件。Spring的核心依赖就在这。
Spring的核心依赖:5+1
spring-core、spring-context、spring-aop、spring-beans、spring-expression
commons-logging(jcl)
写一个入门案例:
- 导入相关依赖:
- 定义一个service
package com.cskaoyan.service;public class HelloService {public void sayHello(String name) {System.out.println("hello " + name);}
}
想要通过Spring容器管理HelloService对象,就得先创建一个Spring容器。
- 创建Spring容器
通过Spring配置文件来管理组件
xml的文件 → 通常名字叫application(-xx).xml
既然是xml文件,文件要满足一定的约束(schema),约束就是规定你书写的格式是什么样的。
约束怎么来?
1、复制已有的配置文件的约束
2、从spring的参考文档上的appendix上复制
3、通过创建文件模板来使用 (推荐)效率高
第一次学习,我们只能通过第二种方式来使用。
有了第一次后,后面再创建Spring配置文件就用第三种方式:
那么,如何创建文件模板?
a. 创建
b. 使用模板
选择自己创建的模板
4. 将组件交给spring管理
组件:交给spring容器管理的实例,我们称之为组件
注册:在spring的配置文件中如何定义实例
HelloService交给Spring管理,这个过程叫做注册
将控制权反转也是通过反射技术来实现的。Spring通过class就能生产处这个类的实例对象。
- 从容器中取出实例进行使用
locTest:
package com.cskaoyan;import com.cskaoyan.service.HelloService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** 入门案例1*/
public class IocTest {@Testpublic void mytest1(){//初始化一个应用上下文,应用上下文是Spring容器一个高级功能的实现//再看ClassPath,表示类加载路径ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");//通过应用上下文从Spring容器中取出组件(实例)HelloService helloSerivce = (HelloService) applicationContext.getBean("helloSerivce");helloSerivce.sayHello("ligenli");}
}
这段代码中用到了ClassPath,下面就来讲一下classpath(类加载路径)。
a. maven的classpath
maven是根据文件夹名和目录结构来决定classpath
--src--main--java--resources
java和resources是maven项目的classpath
4.2idea中的classpath
应用要在idea中跑起来
locTest:
package com.cskaoyan;import com.cskaoyan.service.HelloService;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** 入门案例1*/
public class IocTest {@Testpublic void mytest1() {//初始化一个应用上下文,应用上下文是Spring容器一个高级功能的实现//再看ClassPath,表示类加载路径ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");//通过应用上下文从Spring容器中取出组件(实例)HelloService helloService = (HelloService) applicationContext.getBean("helloService");helloService.sayHello("ligenli");// 1、指定id获得实例对象// 2、指定类型(class)获得实例对象// 3、1+2,即指定id和class//条件:这个类型(class)的组件在容器中只有这一个HelloService helloService2 = (HelloService) applicationContext.getBean(HelloService.class);helloService2.sayHello("加油吧!");HelloService helloService3 = applicationContext.getBean("helloService", HelloService.class);helloService3.sayHello("just be you");}@Testpublic void mytest2(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");//从容器中,取出指定id的组件多次,看是否是同一个组件Object helloService = applicationContext.getBean("helloService");Object helloService2 = applicationContext.getBean("helloService");Object helloService3 = applicationContext.getBean("helloService");Object helloService4 = applicationContext.getBean("helloService");Object helloService1 = applicationContext.getBean("helloService");Assert.assertEquals(helloService,helloService2);}
}
入门案例2
也是通过spring容器管理组件;
管理多个组件 → 多个组件之间有依赖关系
HelloService依赖于HelloDao → 在Spring容器中如何维护多个组件之间的关系
- 导包
- 构建业务代码
HelloDao :
package com.cskaoyan.dao;public interface HelloDao {public void daoSayHello(String name);
}
HelloDaoImpl :
package com.cskaoyan.dao;public class HelloDaoImpl implements HelloDao{@Overridepublic void daoSayHello(String name) {System.out.println("hello " + name);}
}
HelloService :
package com.cskaoyan.service;public interface HelloService {public void sayHello(String name);
}
HelloServiceImpl :
package com.cskaoyan.service;import com.cskaoyan.dao.HelloDao;
import com.cskaoyan.dao.HelloDaoImpl;public class HelloServiceImpl implements HelloService{//我们自己不实例化对象,让Spring来帮我们实例化//HelloDao helloDao = new HelloDaoImpl();HelloDao helloDao;@Overridepublic void sayHello(String name) {helloDao.daoSayHello(name);}public HelloDao getHelloDao() {return helloDao;}public void setHelloDao(HelloDao helloDao) {this.helloDao = helloDao;}
}
- 注册组件并维护组件之间的关系
不能写接口,因为Spring管理组件的底层是通过反射实现的,给一个接口,如何实例化出对象呢?
- 使用
package com.cskaoyan;import com.cskaoyan.dao.HelloDao;
import com.cskaoyan.service.HelloService;
import com.cskaoyan.service.HelloServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest {@Testpublic void mytest(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");//HelloServiceImpl bean = applicationContext.getBean(HelloServiceImpl.class);//spring建议通过接口的类型取出,更容易规范你能去做的事情//比如给spring的组件增强,比如使用jdk动态代理的方式进行增强,那么增强后的组件和接口是相关联的HelloService helloService = applicationContext.getBean(HelloService.class);helloService.sayHello("songge");}@Testpublic void mytest2(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");HelloService helloService = applicationContext.getBean(HelloService.class);helloService.sayHello("songge");HelloDao helloDao = applicationContext.getBean(HelloDao.class);System.out.println(111);}
}
总结:Spring在这里有没有带来新的功能?并没有
调用的都是原有的方法sayHello和daoSayHello
但是提高了组件的重用频率
类似于搭积木,你需要什么样子的,就从容器中取出来。
学习了IOC 和 DI 最大的感触是什么?
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法
依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
Spring 核心API:
ApplicationContextClassPathXmlApplicationContextFileSystemXmlApplicationContext
都是去加载application
ClasspathXmlApplicationContext 加载classpath目录下的配置文件
FileSystemXmlApplicationContext 加载文件系统目录下的配置文件
package com.cskaoyan;import com.cskaoyan.service.HelloService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;public class MyTest {@Testpublic void mytest(){//从classpath加载配置文件→ java或resources目录ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");HelloService bean = applicationContext.getBean(HelloService.class);}@Testpublic void mytest2(){//D:\WorkSpace\j22_workspace\codes\day02-spring-ioc\demo3-applicationContext\src\main\resources\application.xmlString fileSystemPath = "D:\\WorkSpace\\j22_workspace\\codes\\day02-spring-ioc\\" +"demo3-applicationContext\\src\\main\\resources\\application.xml";ApplicationContext applicationContext = new FileSystemXmlApplicationContext(fileSystemPath);}
}
BeanFactory
BeanFactory:容器中所有的组件都是通过这个Bean生产出来的
BeanFactory:生产所有组件bean
FactoryBean:XXXFactoryBean,factoryBean对应的特定的xxx实例。即生产特定的Bean。
讲一个辅助编译的工具:Lombok
帮我们生成getter、setting、equal、hashcode、toString、有参无参构造方法
使用起来非常简单
- 引入依赖
- 安装插件
避免一些编译报错
可以选择离线下载
- 使用lombok
会发现字节码文件中是这样的:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.cskaoyan.component;public class NoArgsConstructorBean {String name;Integer id;public NoArgsConstructorBean() {}public String getName() {return this.name;}public Integer getId() {return this.id;}public void setName(String name) {this.name = name;}public void setId(Integer id) {this.id = id;}public boolean equals(Object o) {if (o == this) {return true;} else if (!(o instanceof NoArgsConstructorBean)) {return false;} else {NoArgsConstructorBean other = (NoArgsConstructorBean)o;if (!other.canEqual(this)) {return false;} else {Object this$name = this.getName();Object other$name = other.getName();if (this$name == null) {if (other$name != null) {return false;}} else if (!this$name.equals(other$name)) {return false;}Object this$id = this.getId();Object other$id = other.getId();if (this$id == null) {if (other$id != null) {return false;}} else if (!this$id.equals(other$id)) {return false;}return true;}}}protected boolean canEqual(Object other) {return other instanceof NoArgsConstructorBean;}public int hashCode() {int PRIME = true;int result = 1;Object $name = this.getName();int result = result * 59 + ($name == null ? 43 : $name.hashCode());Object $id = this.getId();result = result * 59 + ($id == null ? 43 : $id.hashCode());return result;}public String toString() {return "NoArgsConstructorBean(name=" + this.getName() + ", id=" + this.getId() + ")";}
}
通常@AllArgsConstructor和@NoArgsConstructor同时出现
因为增加了有参构造方法会覆盖掉默认的无参构造方法,后续使用框架里底层很多用到反射,反射又经常使用到无参构造方法,通常需要额外增加@NoArgsConstructor
xml文件中注册bean的方式
构造方法
无参构造(最常用)
因为默认提供的是无参构造,这个是最常用
NoArgsConstructorBean :
package com.cskaoyan.component;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 无参构造方法* 默认包含无参的构造方法*/
@Data
@NoArgsConstructor
public class NoArgsConstructorBean {String name;Integer id;
}
在application.xml中的配置:
有参构造:
HasArgsConstructorBean :
package com.cskaoyan.component;import lombok.AllArgsConstructor;
import lombok.Data;/*** 有参构造方法*/
@AllArgsConstructor //写了有参构造方法,会将默认的无参构造方法覆盖掉
@Data
public class HasArgsConstructorBean {String name;Integer id;//public HasArgsConstructorBean(String name, Integer id) {// this.name = name;// this.id = id;//}
}
在application.xml中的配置:
工厂
通常是整合已有代码的时候,可以使用工厂注册组件(比如你写了一个工具类)
实例工厂:
静态工厂:
生命周期:
Spring中bean的生命周期
并不是所有的bean都会执行完所有的声明周期。
默认只会执行到1和2。之后这些需要满足一定的条件才能执行到。
6和9做的事情很类似,只不过和7、8之间有一个顺序关系。
默认是不会执行红框框中的生命周期的,只有实现了这些接口才会执行。
LifeCycleBean代码:
CustomBeanPostProcessor代码:
测试代码:
package com.cskaoyan.bean;import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class LifeCycleTest {@Testpublic void mytest1(){//执行完这行代码就意味着组件可以使用了,也就是1-9的生命周期都执行完了ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");//不需要取出组件,生命周期就已经开始//关闭上下文后就会执行10、11生命周期applicationContext.close();}
}
执行结果:
可以利用生命周期的先后顺序写一些简单的业务逻辑。
作业:使用spring为项目里的所有类的所有方法增加
写几个不同的bean ,每个bean里包含不同的方法。
通过spring 使得调用任何一个实现方法之前和之后都增加一些内容输出。(通过PostBeanProcessor实现)
提示:生命周期 动态代理
提示:狸猫换太子
举个例子:比如有几个类Cat、Dog、Tiger,这几个类中分别有miao、wang、wuuu这几个方法,那么从容器中取出组件,调用这几个方法的时候(注意不是容器初始化时),miao、wang、wuuu这几个方法执行之前都会输出hello,执行之后都会输出world
这篇关于week15_day02_Spring_IOCDIApplicationContextlombokxml文件中注册bean的方式生命周期的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!