tiny-Spring【1】
Spring框架的两大特性:IOC、AOP
1,IOC特性
IOC:IOC,另外一种说法叫DI(Dependency Injection),即依赖注入。它并不是一种技术实现,而是一种设计思想。
在任何一个有实际开发意义的程序项目中,我们会使用很多类来描述它们特有的功能,并且通过类与类之间的相互协作来完成特定的业务逻辑。这个时候,每个类都需要负责管理与自己有交互的类的引用和依赖,代码将会变的异常难以维护和极度的高耦合。而IOC的出现正是用来解决这个问题,我们通过IOC将这些相互依赖对象的创建、协调工作交给Spring容器去处理,每个对象只需要关注其自身的业务逻辑关系就可以了。在这样的角度上来看,获得依赖的对象的方式,进行了反转,变成了由Spring容器控制对象如何获取外部资源(包括其他对象和文件资料等等)。
大白话就是:
我们在完成一些生产生活劳作【业务逻辑】的时候,需要使用到其他的工具【其他实例化对象-如斧头、镰刀、马车等】;在之前我们都是自己去实例化【自给自足-手动new一个个工具】,效率很低。
到了现代社会【Spring类似框架出现后】,我们自用关注我们的工作和生活就行了,其他的那些工具交给这个现代社会【Spring来进行对象的实例化】去完成。
以前是,我们主动去new一个工具,现在变成被动的接收工具。你现在不可能自己去造一辆地铁了吧!直接我要用的话,直接去用就完事了。
2,AOP特性
AOP:面向切面编程,往往被定义为促使软件系统实现关注点的分离的技术。
系统是由许多不同的组件所组成的,每一个组件各负责一块特定功能。除了实现自身核心功能之外,这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的核心服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点,因为它们会跨越系统的多个组件。
通知: 通知定义了切面是什么以及何时使用的概念。Spring 切面可以应用5种类型的通知:
- 前置通知(Before):在目标方法被调用之前调用通知功能。
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
- 返回通知(After-returning):在目标方法成功执行之后调用通知。
- 异常通知(After-throwing):在目标方法抛出异常后调用通知。
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
连接点:是在应用执行过程中能够插入切面的一个点。
切点: 切点定义了切面在何处要织入的一个或者多个连接点。
切面:是通知和切点的结合。通知和切点共同定义了切面的全部内容。
引入:引入允许我们向现有类添加新方法或属性。
织入:是把切面应用到目标对象,并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期中有多个点可以进行织入:
编译期: 在目标类编译时,切面被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载期:切面在目标加载到JVM时被织入。这种方式需要特殊的类加载器(class loader)它可以在目标类被引入应用之前增强该目标类的字节码。
运行期: 切面在应用运行到某个时刻时被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的。
3,tiny-Spring
参考-黄亿华的tiny-Spring
3.1 Step1
BeanFactory.java工厂模式接口
package com.cnblogs.Factory; public interface BeanFactory {
/**
* 工厂模式中的接口,用于产生实体类
* @param name
* @return
* @throws Exception
*/
Object getBean(String name) throws Exception;
}
AbstractBeanFactory.java注册表类型【登记已经有的实例】
package com.cnblogs.Factory; import com.cnblogs.bean.BeanDefinition; import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; public class AbstractBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<String, BeanDefinition>();//线程安全-散列表
private final List<String> beanDefinitionNames=new ArrayList<String>();//实体对象名称 @Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition=beanDefinitionMap.get(name);
if(beanDefinition==null){
throw new IllegalArgumentException("No bean named"+name+" is defined");
}
Object bean=beanDefinition.getBean(name);
return bean;
} //本质上就是进行名称和对象的映射到散列表上
public void registerBeanDefinition(String name,BeanDefinition beanDefinition) throws Exception{
beanDefinitionMap.put(name,beanDefinition);
beanDefinitionNames.add(name);
}
}
BeanDefinition.java 传入实例【类似包装盒的作用-里面的东西可以千差万别】
package com.cnblogs.bean; /**
* bean的内容及元数据,保存在BeanFactory中,包装bean的实体
*/ public class BeanDefinition {
private Object bean;
private Class<?> beanClass;
private String beanClassName;
public BeanDefinition(){}
public BeanDefinition(Object object){
this.bean=object;
} public void setBeanClassName(String beanClassName) throws ClassNotFoundException {
this.beanClassName=beanClassName;
try{
this.beanClass=Class.forName(beanClassName);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
} }
Client.java测试类
import com.cnblogs.Factory.AbstractBeanFactory;
import com.cnblogs.Factory.BeanFactory;
import com.cnblogs.bean.BeanDefinition; class HelloWorldServiceImpl { public void helloWorld2() {
System.out.println("hello");
}
} public class Client {
public static void Step1() throws Exception{
BeanFactory beanFactory=new AbstractBeanFactory();
BeanDefinition beanDefinition=new BeanDefinition(new HelloWorldServiceImpl()); ((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld",beanDefinition); HelloWorldServiceImpl h=(HelloWorldServiceImpl) beanFactory.getBean("helloworld");
h.helloWorld2();
} public static void main(String[] args) throws Exception {
Client.Step1();
}
}
3.2 Step2【利用反射机制传入String 类名-实例化对象】
public static void Step2() throws Exception{
BeanFactory beanFactory=new AbstractBeanFactory();//无参构造,不传入实例
BeanDefinition beanDefinition=new BeanDefinition();
beanDefinition.setBeanClassName("com.spring.step1.test.HelloWorldServiceImpl"); ((AbstractBeanFactory) beanFactory).registerBeanDefinition("helloworld",beanDefinition); HelloWorldServiceImpl h=(HelloWorldServiceImpl) beanFactory.getBean("helloworld");
h.helloWorld2();
}
AbstractBeanFactory/getBean()方法
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition=beanDefinitionMap.get(name);
if(beanDefinition==null){
throw new IllegalArgumentException("No bean named "+name+" is defined");
}
Object bean=beanDefinition.getBean();
if (bean==null) {
Constructor constructor=beanDefinition.getBeanClass().getDeclaredConstructor();
constructor.setAccessible(true);//设置权限
bean=constructor.newInstance();
beanDefinition.setBean(bean);
}
return bean;
}
3.3 step3【注入参数】
之前的实体类HelloWorldServiceImpl中有属性后
private String text;
private int a;
HelloWorldServiceImpl实体类
class HelloWorldServiceImpl {
private String text;
private int a; public HelloWorldServiceImpl(){} public void helloWorld2(){
System.out.println("hello");
} public void helloWorld3() {
System.out.println(text + a + " ss");
}
}
PropertyValue封装类
package com.spring.step1.bean; /**
* 用于bean的属性注入
* 和BeanDefinition一个效果,将实体进行封装到一个动态类中
*/
public class PropertyValue {
private final String name;
private final Object value; // 省略get/set 后文对简单的get/set方法将直接省略 不再说明 public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
} public String getName() {
return name;
} public Object getValue() {
return value;
}
}
PropertyValues封装类
package com.spring.step1.bean; import java.util.ArrayList;
import java.util.List; /**
* 包装一个对象所有的PropertyValue。<br/>
* 为什么封装而不是直接用List?因为可以封装一些操作。
* 单纯的一个ArrayList对象,其中封装了一些实体对象
*/
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
public PropertyValues(){} public void addPropertyValue(PropertyValue pv){
//TODO:这里可以对于重复propertyName进行判断,直接用list没法做到
// System.out.println(pv.getName()+pv.getValue());
this.propertyValueList.add(pv);
}
public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}
}
在BeanDefinition里加入【private PropertyValues propertyValues;】setter和getter默认
AbstractBeanFactory类中的getBean也要进行相关修改
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition=beanDefinitionMap.get(name);
if(beanDefinition==null){
throw new IllegalArgumentException("No bean named "+name+" is defined");
} Object bean=beanDefinition.getBean();
if (bean==null) {
Constructor constructor=beanDefinition.getBeanClass().getDeclaredConstructor();
constructor.setAccessible(true);//设置权限
bean=constructor.newInstance();
constructor.setAccessible(false);//设置权限
beanDefinition.setBean(bean);
}
creatBean(bean, beanDefinition);
return bean;
} public void creatBean(Object bean, BeanDefinition beanDefinition) throws Exception{
if(beanDefinition.getPropertyValues() != null)
creatBeanWithProperty(bean, beanDefinition);
} public void creatBeanWithProperty(Object bean, BeanDefinition beanDefinition) throws Exception{
int size =beanDefinition.getPropertyValues().getPropertyValues().size();//List长度
List<PropertyValue> list = beanDefinition.getPropertyValues().getPropertyValues();//由外及内
for (int i = 0; i <size ; i++) {
if(list.get(i).getValue() instanceof BeanReference) {
String beanName = ((BeanReference) list.get(i).getValue()).getName();
Object referenceBean = getBean(beanName);
String ms = "set" + Character.toUpperCase(list.get(i).getName().charAt(0)) + list.get(i).getName().substring(1);
Method m = bean.getClass().getDeclaredMethod(ms, referenceBean.getClass());//反射机制的数据配置-初始化处理
m.invoke(bean, referenceBean);
}else {//手动进行赋值
String fieldName = list.get(i).getName();
Object value = list.get(i).getValue();
Field field = bean.getClass().getDeclaredField(fieldName); // getDeclaredField是获得所有的字段(不仅仅是public)
field.setAccessible(true); // 这一步必须有
field.set(bean, value);
field.setAccessible(false); // 这一步必须有
}
}
}
测试类step3
public static void Step3() throws Exception {
// 1.初始化beanfactory
BeanFactory beanFactory = new AbstractBeanFactory();
// 2.bean定义
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanClassName("com.spring.step1.test.HelloWorldServiceImpl");
// 3.设置属性
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("text","Hello World!"));
propertyValues.addPropertyValue(new PropertyValue("a",new Integer(15)));
beanDefinition.setPropertyValues(propertyValues);
// 4.注册bean
((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld", beanDefinition); HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory.getBean("helloworld");
h.helloWorld3();
}
3.4 step4【加入引用变量】
引用实体类
package com.spring.step1.test; public class OutputService {
public static void output(String text){
System.out.println(text);
}
}
加入引用变量
参考链接:
https://blog.csdn.net/it_man/article/details/4402245【这个讲的很清楚啊,举得例子和现实很贴切】
https://blog.csdn.net/dlf123321/article/details/39994071
tiny-Spring【1】的更多相关文章
- spring 【二】学习之spring EL
spring EL-spring 表达式语言,支持在xml和注解的形式,类似于JSP的el表达式的形式. 其主要使用@Value注解的结构形式 其主要功能 [1].注入普通字符串 [2].注入操作系统 ...
- Spring【AOP】
AOP是OOP的延续,是软件开发中的一个热点. AOP技术,是OOP补充. OOP引入封装.继承和多态建立一种对象层次结构模拟公共行为集合,而对从左到右的关系则显得无能为力.对于AOP则恰恰适应这样的 ...
- spring【一】 学习
Spring 源码学习 通过注解的形式注入IOC 简单的创建一个maven的项目的 下载指定的spring的核心jar包(https://mvnrepository.com/artifact/org. ...
- Spring【基础】-注解-转载
站在巨人的肩膀上,感谢! https://blog.csdn.net/chjttony/ 1.在java开发领域,Spring相对于EJB来说是一种轻量级的,非侵入性的Java开发框架, 曾经有两本很 ...
- 【核心核心】8.Spring【AOP】注解方式
1.引入jar包 sprig框架基础包+JUntil整合包+日志包+AOP包 spring的传统AOP的开发的包 spring-aop-4.2.4.RELEASE.jar com.springsour ...
- 6.Spring【AOP】XML方式
1.AOP术语 1. Joinpoint(连接点):所谓连接点是指那些被拦截到的点.在spring中,这些点指的是方法,因为spring只支持方法类型的连接点 2. Pointcut(切入点):所谓切 ...
- 【核心核心】4.Spring【IOC】注解方式
1.导入jar包 2.创建对应的类 public interface HelloService { public void sayHello(); } /** * @Component(value=& ...
- 2.Spring【DI】XML方式
依赖: 在A类中引用了B类,说明A依赖于B. 注入: 使用Spring框架给A类中的B对象的属性赋值. 直接上代码: 1.只使用IOC public class Person { private St ...
- 1.Spring【IOC】XML方式
1.下载开发包 http://repo.springsource.org/libs-release-local/org/springframework/spring 2.创建WEB工程,引入jar包 ...
- eclipse之SSH配置spring【二】
第一篇中配置struts完成(http://www.cnblogs.com/dev2007/p/6475074.html),在此基础上,继续配置spring. web.xml中增加listener,依 ...
随机推荐
- Pandas的Categorical Data
http://liao.cpython.org/pandas15/ Docs » Pandas的Categorical Data类型 15. Pandas的Categorical Data panda ...
- hibernate的各种查询
Hibernate Query Language(HQL)Criteria QueryNative SQL下面对其分别进行解释select子句:有时并不需要取得对象的所有属性,这时可以使用select ...
- PYNQ系列学习(二)——pynq与zynq对比(一)
Zynq可扩展处理平台是赛灵思新一代 FPGA的可编程技术的产品系列.与采用嵌入式处理器的FPGA不同,Zynq产品系列的处理系统不仅能在开机时启动,而且还可根据需要配置可编程逻辑.采用这种方法,软件 ...
- LC 991. Broken Calculator
On a broken calculator that has a number showing on its display, we can perform two operations: Doub ...
- 解读typescript中 super关键字的用法
解读typescript中 super关键字的用法 传统的js,使用prototype实现父.子类继承.如果父.子类有同名的方法,子类去调用父类的同名方法需要用 “父类.prototype.metho ...
- [webpack]深入学习webpack核心模块tapable
一.手动实现同步钩子函数 1.SyncHook class SyncHook { // 钩子是同步的 constructor(args){ this.tasks = []; } tap(name,ta ...
- 002-02-RestTemplate-初始化调用流程
一.简述 调用 RestTemplate 的默认构造函数,RestTemplate 对象在底层通过使用 java.net 包下的实现创建 HTTP 请求,可以通过使用 ClientHttpReques ...
- 17flutter中的路由/命名路由/命名路由传值/无状态组件传值/有状态组件传值。
main.dart import 'package:flutter/material.dart'; import 'package:flutter_demo/pages/Search.dart'; i ...
- Rust基础笔记:闭包
语法 Closure看上去是这样的: let plus_one = |x: i32| x + 1; assert_eq!(2, plus_one(1)); 首先创建一个绑定plus_one,然后将它分 ...
- CentOS7下搭建zabbix监控(二)——Zabbix被监控端配置
Zabbix监控端配置请查看:CentOS7下搭建zabbix监控(一)——Zabbix监控端配置 (1).在CentOS7(被监控端)上部署Zabbix Agent 主机名:youxi2 IP地址: ...