Spring入门 及 模拟springioc
简介
spring:是一个大型的容器,用来管理协调各层之间的调用。
1. 核心:
- IOC/DI:控制反转/依赖注入 Inversion of Control/Dependency Injection.
- AOP:Asepct Oriented Programming.
2. spring特点:
- 轻量级:不是因为其代码量少,而是spring是非侵入式的。及基于spring开发的应用,不需要依赖spring api,即在使用spring时,无需实现或继承spring的任何接口或父类。
- 容器:因为spring包含并管理应用对象的生命周期。
- 一站式框架:在IOC和AOP基础上,可以整合各种企业应用的开源框架。
创建第一个Spring项目
这里参考官方文档:https://spring.io/
这里使用maven进行构建。
1. 导入相关依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring的依赖包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
2. 创建实体类
private int deptno;
private String dname;
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
3. 创建spring的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">
<!-- 需要spring ioc容器管理的类 -->
<bean id="dept" class="com.hx.spring.Dept">
<!--id:根据id注值 class:根据类路径注入 -->
<property name="deptno" value="101"></property>
<property name="dname" value="技术部"></property>
</bean>
</beans>
4. 创建测试类
@Test
public void test1(){
//实例化ioc容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
//从容器中获取所需要的对象
Dept dept = (Dept) context.getBean("dept"); //括号中填写xml中配置的实体类的id
System.out.println(dept);
}
模拟springioc
1. 创建ClassDefinition类
/**
* 类定义,用来解析每个类的信息
* @author Huathy
* @date 2020年3月4日
*/
public class ClassDefinition {
private String id; //唯一标识
private String className; //类的全路径
private Map<String,String> pros;
public ClassDefinition(String id, String className) {
super();
this.id = id;
this.className = className;
pros = new HashMap<String,String>();
}
public void addPro(String key, String value) {
pros.put(key, value);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Map<String, String> getPros() {
return pros;
}
public void setPros(Map<String, String> pros) {
this.pros = pros;
}
}
2. 创建 ApplicationContext 接口
/**
*
* @author Huathy
* @date 2020年3月4日
*/
public interface ApplicationContext {
public Object getBean(String id);
}
3. 创建 ClassPathXmlApplicationContext 类
/**
*
* @author Huathy
* @date 2020年3月4日
*/
public class ClassPathXmlApplicationContext implements ApplicationContext {
private Map<String,Object> singeton = new HashMap<String,Object>();
private List<ClassDefinition> beans = new ArrayList<>();
public ClassPathXmlApplicationContext(String path) {
parseXml(path);
try {
makeInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
private void makeInstance() throws Exception {
if(beans.isEmpty()){
return;
}
Class c = null;
Method[] methods = null;
Map<String,Method> map = null;
String methodName = null;
Object obj = null;
Map<String,String> properties = null;
Method md = null;
String typeName = null;
for(ClassDefinition cls : beans){
c = Class.forName( cls.getClassName() );
obj = c.newInstance();
properties = cls.getPros();
if(properties == null || properties.isEmpty()){
singeton.put(cls.getId(), obj);
continue;
}
methods = c.getDeclaredMethods();
map = new HashMap<String,Method>();
for(Entry<String, String> entry : properties.entrySet()){
methodName = entry.getKey();
methodName = "set" + methodName.substring(0,1).toUpperCase() + methodName.substring(1);
md = map.get(methodName);
if(md == null){
continue;
}
typeName = md.getParameterTypes()[0].getSimpleName();
if( "int".equals(typeName) || "Integer".equals(typeName) ){
md.invoke(obj, Integer.parseInt(entry.getValue()));
}else if( "float".equals(typeName) || "Float".equals(typeName) ){
md.invoke(obj, Float.parseFloat(entry.getValue()));
}else if( "double".equals(typeName) || "Double".equals(typeName) ){
md.invoke(obj, Double.parseDouble(entry.getValue()));
}else{
md.invoke(obj, entry.getValue());
}
}
singeton.put(cls.getId(), obj);
}
}
/**
* 解析xml文件
* @param path
*/
private void parseXml(String path){
SAXReader read = new SAXReader();
Document doc = null;
try(InputStream is = this.getClass().getClassLoader().getResourceAsStream(path)){
doc = read.read(is);
XPath xpath = doc.createXPath("//hx:bean"); //查找hx下的bean
//这里需要对命名空间进行处理
Map<String,String> nsmap = new HashMap<>();
nsmap.put("hx", "http://www.springframework.org/schema/beans"); //使用hx来替代后面的
xpath.setNamespaceURIs(nsmap); //设置命名空间信息
List<Element> nodes = xpath.selectNodes(doc);
if(nodes.isEmpty()){
return; //判断xml中是否配置,如果没有配置,直接返回
}
String id = null;
String className = null;
ClassDefinition bean = null;
List<Element> properties = null;
for(Element el : nodes){
id = el.attributeValue("id");
className = el.attributeValue("class");
bean = new ClassDefinition(id, className);
properties = el.elements(); //取出这个bean对象的属性值
if(properties != null && !properties.isEmpty()){
for(Element pro : properties){ //循环所有属性值
bean.addPro(pro.attributeValue("name"),pro.attributeValue("value"));
}
}
beans.add(bean);
}
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String id) {
return singeton.getOrDefault(id, null);
}
}
4. 创建实体类、xml配置文件、测试类
- 实体类
public class Dept implements Serializable{
private int deptno;
private String dname;
private List<Emp> emps;
public List<Emp> getEmps() {
return emps;
}
public void setEmps(List<Emp> emps) {
this.emps = emps;
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + deptno;
result = prime * result + ((dname == null) ? 0 : dname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dept other = (Dept) obj;
if (deptno != other.deptno)
return false;
if (dname == null) {
if (other.dname != null)
return false;
} else if (!dname.equals(other.dname))
return false;
return true;
}
@Override
public String toString() {
return "Dept [deptno=" + deptno + ", dname=" + dname + "]";
}
public Dept(int deptno, String dname) {
super();
this.deptno = deptno;
this.dname = dname;
}
public Dept() {
super();
}
}
- xml配置文件spring-beans.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">
<!-- 需要spring ioc容器管理的类 -->
<bean id="dept" class="com.hx.spring.entity.Dept">
<!-- class:根据类路径注入 -->
<property name="deptno" value="101"></property>
<property name="dname" value="技术部"></property>
</bean>
</beans>
- 测试类
public class AppTest {
@Test
public void test1(){
//实例化ioc容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
//从容器中获取所需要的对象
Dept dept = (Dept) context.getBean("dept"); //括号中填写xml中配置的实体类id
System.out.println(dept);
}
}