Spring的扩展

Posted cgblpx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring的扩展相关的知识,希望对你有一定的参考价值。

模拟SpringIoC的实现

概念

SpringIoC控制反转底层实现利用了java自身提供的反射技术来创建对象

Class.forName(classPath).newInstance();

通过这种方式,spring控制了对象的生命周期,可以随时自行增强对象,如DI依赖注入,如AOP,环绕通知在类创建前后增强功能,如Transaction事务加强等。

开发步骤

  1. 创建容器管理bean,并初始化容器-> [user,dept,hello]
  2. 创建spring容器,并初始化容器-> {hello=new Hello(),user=new Uer() }
  3. 提供getBean(),根据bean的名字,从spring容器中获取对应的对象

Bean.java

抽象Bean的定义,取代java中的Object,Spring框架中万物皆Bean。

package cn.tedu.design;
//模拟spring管理bean,存放bean
public class Bean {
	private String name;//bean名字-> hello
	private String path;//bean对应的类路径->cn.tedu.desing.Hello
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	
}

SpringContext.java

逻辑复杂,IoC实现的核心,最关键点还是怎么创建对象实例:

package cn.tedu.design;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
//模拟spring框架,是spring的核心
//1,创建容器管理bean-> [user,dept,hello]
//2,创建spring容器-> {hello=new Hello(),user=new Uer() }
//3,getBean(),有就直接取出来,没有就创建并放入容器
public class SpringContext {
	//1,创建容器管理bean-> [user,dept,hello]
	private List<Bean> beanFactory = new ArrayList<>();
	//初始化容器
	public SpringContext() throws Exception {
		//创建Bean,并加入容器中
		Bean bean = new Bean();
		bean.setName("hello");
		bean.setPath("cn.tedu.pojo.Hello");
		beanFactory.add(bean);
		init();
	}
//2,创建spring容器-> {hello=new Hello(),user=new Uer() }   //并发安全的map
	private final Map<String, Object> factoryBeanObject = new ConcurrentHashMap<>();
	//初始化spring容器-> {hello=new Hello(),user=new Uer() } 
	public void init() throws Exception {
		//遍历beanFactory,得到每个bean
		for(Bean b : beanFactory) {
			//map里的key
			String key = b.getName();
			//反射创建对象,作为value存入map
			String path = b.getPath();
			Object value = Class.forName(path).newInstance();
			factoryBeanObject.put(key, value);
		}
	}
	//3,getBean()有就直接取出来,没有就创建并放入容器
	public Object getBean(String name) {
		return factoryBeanObject.get(name);//去map里根据key找value
	}
	
}

Hello.java

package spring;

public class Hello {
	public void hi() {
		System.out.println("hi springioc");
	}
}

TestMyIoC.java

package cn.tedu.spring;

import cn.tedu.design.SpringContext;
import cn.tedu.pojo.Hello;

public class TestMyIOC {
	public static void main(String[] args) throws Exception {
		SpringContext spring = new SpringContext();
		Hello o = (Hello)spring.getBean("hello");
		System.out.println(o);//cn.tedu.pojo.Hello@6d06d69c
		o.hi();
	}
}

模拟SpringDI的底层实现

Student.java

package cn.tedu.designdi;

import org.springframework.stereotype.Component;

@Component
public class Student {
    private String name="王一博";

    @MyAutowired //di
    private Teacher teacher;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\\'' +
                ", teacher=" + teacher +
                '}';
    }
}

Teacher.java

package cn.tedu.designdi;

import org.springframework.stereotype.Component;

@Component
public class Teacher {
    private String name="皮皮霞";

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\\'' +
                '}';
    }
}

自定义注解

package cn.tedu.designdi;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
    String value() default  "" ;
}

TestMyDI.java

package cn.tedu.designdi;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Field;

//有注解的属性就new
public class TestDI {
    @Test
    public void di() throws Exception{
        //获取Student类里的属性,哪个属性有MyAutowired注解就给他new一个
        Class s = Class.forName("cn.tedu.designdi.Student");
        Object o = s.newInstance();
        Field[] fs = s.getDeclaredFields();
        for (Field f : fs) {
            MyAutowired an = f.getAnnotation(MyAutowired.class);
            if(an != null){
                f.setAccessible(true);
                f.set(o,new Teacher());
            }
        }
//        Student{name='王一博', teacher=Teacher{name='皮皮霞'}}
        System.out.println((Student)o);
    }
}

Spring整合SpringMVC的项目实战

Spring用来管理项目中的所有Bean,需要使用注解@Component @Autowired @Service @Component等

Springmvc用来管理Controller层,需要使用的注解有@RestController @RequestMapping等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cPl5tW93-1623125484759)(RackMultipart20210608-4-9jbi5w_html_a71a298b5faabd1f.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lwPTMiRw-1623125484761)(RackMultipart20210608-4-9jbi5w_html_dce2bb2f55ba2790.png)]

需求

访问链接: http://localhost:8080/car/get
得到JSON数据: {"name":"保时捷","color":"红色","price":641000.0}

项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UKL93CQl-1623125484763)(RackMultipart20210608-4-9jbi5w_html_385e249cd30a3b66.png)]

创建RunApp.java

package cn.tedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RunApp {
	public static void main(String[] args) {
		SpringApplication.run(RunApp.class);
	}
}

创建application.yml文件

\\ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ewwdgKa-1623125484764)(RackMultipart20210608-4-9jbi5w_html_29b37e342a91ddee.png)]

server:
  port: 8090

创建Car类

package cn.tedu.pojo;

import org.springframework.stereotype.Component;

@Component
public class Car {
    private String name ;
    private String color;
    private double price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\\'' +
                ", color='" + color + '\\'' +
                ", price=" + price +
                '}';
    }
}

创建CarService接口

package cn.tedu.service;

import cn.tedu.pojo.Car;

public interface CarService {
    Car get();
}

创建CarServiceImpl实现类

package cn.tedu.service;

import cn.tedu.pojo.Car;
import org.springframework.stereotype.Service;

@Service
public class CarServiceImpl implements CarService{
    @Override
    public Car get() {
        Car c = new Car();
        c.setName("保时捷");
        c.setColor("红色");
        c.setPrice(641000.0);
        return c;
    }
}

创建CarController类

package cn.tedu.controller;

import cn.tedu.pojo.Car;
import cn.tedu.service.CarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/car/")
public class CarController {
    @Autowired
    private CarService carService;

    @RequestMapping("get")
    public Car get(){
        return carService.get();
    }
}

测试

打开浏览器访问:http://localhost:8090/car/get

以上是关于Spring的扩展的主要内容,如果未能解决你的问题,请参考以下文章

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段

Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]

What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段

解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE(转)(代码片段