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,依 ...
随机推荐
- 灵活使用ssh、dsh和pssh高效管理大量计算机
http://os.iyunv.com/art/201012/240113.htm 灵活使用ssh.dsh和pssh高效管理大量计算机 http://os.iyunv.com2010-12-23 09 ...
- 单硬盘根分区扩容(非LVM)
单用户模式(内核参数末尾加single)救援模式(用光盘启动,选第三个,rescue installed system) 救援模式有什么作用: 1可以更改root密码:2恢复硬盘.文件系统操作:3系统 ...
- Android:系统日历添加默认账户
@@ -190,9 +191,47 @@ public class AllInOneActivity extends AbstractCalendarActivity implements Event ...
- 一百四十四:CMS系统之评论布局和功能二
在base页加一个登录标识符 给加页面两个id,方便取值 js $(function () { //初始化ueditor var ue = UE.getEditor('editor', { 'serv ...
- Python基础之内置函数(二)
先上一张图,python中内置函数: python官方解释在这:点我点我 继续聊内置函数: callable(object):检查对象是否可被调用,或是否可执行,结果为bool值 def f1(): ...
- 使用wsimport生成webservice客户端代码
服务端 package com.xc.webservice; import javax.jws.WebService; import javax.xml.ws.Endpoint; @WebServic ...
- 国内强大的API接口文档写作网站showdoc
传送门:https://www.showdoc.cc/ 思思今天使用了一下,真是非常方便,瞬间爱上呀,哈哈. 赶紧去试试吧...
- Python3之高阶函数sorted
排序算法 Python内置的sorted()函数可以对list进行排序 >>> sorted([36,5,-12,9,-21]) [-21, -12, 5, 9, 36] 此外,so ...
- iOS-UIWebView去掉滚动条和黑色背景即拖拽后的上下阴影
iOS UIWebView去掉滚动条和黑色背景即拖拽后的上下阴影 隐藏滚动条和上下滚动时出边界的后面的黑色的背景 webView.backgroundColor=[UIColor clearColor ...
- linux中安装docker
uname -r yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ ...