我的第一篇博客《浅谈SSH框架原理,并模仿实现Spring中Aop框架》
来源:互联网 发布:知来者之可追什么意思 编辑:程序博客网 时间:2024/04/30 03:14
这篇日志,是在我今天应聘JAVA软件工程师,那个招聘人员问我:“SSH框
架的核心原理是什么?”,由此引发的一些感想,虽然那时答的有点不好,SSH框架
的核心原理是什么?我回答是的反射技术。真是这样的吗?回到宿舍,网上看了些资
料,才知道了自己回答的确实不妥。
SSH中struts框架它是MVC(Model-View-Contraller)的实现,它是用于
处理数据库里数据和界面(jsp)中的数据的传输。
Model层,是以一个或者多个JavaBean形式出现的。也就是我们平时写的实体类中的
Java类。它可以存储通过Contraller中取得的数据,并通过get和set方法来操作这些
数据。
View层,也就是我们平常所编写的JSP界面,当然Struts还为我们提供了丰富的JSP标
签库,S标签,Template等,这有利于分开表现逻辑和程序逻辑。
Contraller层中的角色采用的是一个Servlet,叫ActionServlet,也就是我们平时
使用SSH框架中所编写的Action类(需继承ActionSupport),它控制一些从Hibernate
中框架中查询出来的数据。
SSH中的Spring框架的精髓是它的IOC(Inversion of Control,反向控制)
模式实现的BeanFactory(Bean工厂)和AOP(面向切面编程),它的底层是采用动态代
理技术和反射技术来实现的。它解释起来有点麻烦,假设,现在我们所用的类到Java
程序运行期才知道,我们怎么样做呢?如Collection collection = new
ArrayList();或者Collection collection = new HashSet();这里的ArrayList或
者HashSet的名字,我们编译期时还不知道要用那个,到执行期才知道用那个,又或
者我们要随时变化使用这两个ArrayList、HashSet中的一个,在只写了一份代码的情
况下,我们该怎么做呢?Spring就给我们解决了这样的问题,它在配置文件中配置我
们所需要用的ArrayList或者HashSet通过反射技术来得到所要使用的ArrayList或者
HashSet。由于Spring涉及的技术比较底层。这里先解释到这里,等下,讲解我
Hibernate的原理后,我在自己实现一个微型的spring框架,这时,我们也许就会明
了了。
SSH框架中的Hibernate框架,它是干嘛的呢?简单的说,它是用来处理数据
库的数据的,例如连接数据库,对数据库进行增删改查都是它进行处理的。简单的就
是它把以前我们所用写的JDBC与一些数据库的操作都进行了封装,并提供给你接口使
用。当然它也提供了一些其他技术,如JNDI和JIA等。
好了,简单解释了下SSH框架后,我们来实现我所谓的微型的spring框架。
这实现它之前,我需讲解下它所用的技术的是什么,它所用的技术也就是Java中的动
态代理和反射技术。现在先解释下什么叫动态代理:其实它很好理解,例如,我们生
活中我们要去买瓶可乐,我们不是直接去找生产商去买,我们而是去找代理商去买,
本来这个可乐只是生产商才能生产的,但是代理商去找生产商去批发,我们再去代理
商去买,就省了我们去生产商那里去买了。这里的代理商就是我要说的生活中的代理
。当然Java代码中的代理又是怎么样的呢?它是这样的,假如我们要去执行目标类,
我们这时不直接执行目标类,而是通过代理类来执行,不过代理类实现了目标类的相
同的接口。也许有人会问,这样有什么好处呢?当然有好处啊,这时我们可以再执行
代理类的同时可以去执行一些其他的系统功能啊,如日志功能,系统功能等。这就是
Java中所谓的代理技术。当然这里可能涉及到Spring中的Aop(面向切面编程,简单
来讲就是交叉业务的编程问题)技术,因为日志功能,系统功能等这些功能可能涉及
到多个业务层中。当然了Java中存在静态代理和动态代理之分:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,
代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。当然我们要编写微型Spring
框架我们就需采用动态代理技术了。因为有些类,我们在运行期才知道,我们事先没
法知道用户要采用哪些类。
解释完,代理技术后,现在来解释下反射技术,什么叫反射?反射就是把
JAVA类中的各个成员成分映射成相应的java类,当然这不是我讲的,这是那些编程高
手讲的。怎么理解呢?我的理解是Java类中的各个属性,字段,方法,构造函数,接
口等,都可以通过它的类的字节码来取得它们所对应的类的对象。如取得字段属性对
象:Field field = 类.class.getField("y");取得字段y的对象。这里就可以解决
上面,我们运行期才知道名字怎么取得它的对象的问题了。
Collection collection = (ArrayList)Class.forName
(className).getConstructor(ArrayList.class).newInstance(new ArrayList
());这里的className从配置文件中取得,我们通过反射技术取得所用的类的构造函
数,并且通过实例化对象来取得类对象。我们编写这个微型Spring框架这采用JVM中
提供的Proxy来生成的动态代理类。所以这里也把Proxy所涉及的类和接口说下。
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws
Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉
ProxySubject。
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现
类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[]
interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
这里又出现个新词类加载器:类加载器其实也是一个类的对象
java为我们提供了三类类加载器分别为
BootStrap,ExtClassLoader,AppClassLoader
它们分别加载jdk/jre/rt.jar,jdk/jre/ext/*.jar,classpath下的class文件
它们也是祖,父,子的关系。它们中存在委托的机制,当一个类要使用类加载器时,
这时AppClassLoader类加载器会委托给ExtClassLoader类加载器去找,
ExtClassLoader会委托给BootStrap去找BootStrap找到了就使用,没有找到,让
ExtClassLoader去找,ExtClassLoader也一样,没有找到让AppClassLoader去找,
AppClassLoader没有找到则抛出异常(除非你自定义类加载器)。
BeanFactory.java
/**
* Bean工厂,用来根据配置文件取得其Bean
* @author Administrator
*
*/
public class BeanFactory {
Properties properties = new Properties();
/**
* 根据输入流取得Properties对象
* @param ips
*/
public BeanFactory(InputStream ips){
try {
properties.load(ips);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Object getBean(String name) throws Exception{
String className = properties.getProperty(name);//根据
名字取得配置文件中所对应的类的名字
Object bean = Class.forName(className).newInstance();//
根据类的名字取得配置文件中所对应的类
if(bean instanceof ProxyFactoryBean){//判断配置文件是否
要求生成代理
ProxyFactoryBean proxyBean =
(ProxyFactoryBean)bean;
Advice advice = (Advice)Class.forName
(properties.getProperty(name+".advice")).newInstance();
Object target = Class.forName
(properties.getProperty(name+".target")).newInstance();
proxyBean.setAdvice(advice);
proxyBean.setTarget(target);
Object proxy = proxyBean.getProxy();//得到代理
return proxy;
}
return bean;
}
}
ProxyFactoryBean.java
/**
* 根据类对象生成代理
* @author Administrator
*
*/
public class ProxyFactoryBean {
private Object target;
private Advice advice;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getProxy() {
Object proxy = (Object)Proxy.newProxyInstance(
target.getClass().getClassLoader(), //
类加载器
target.getClass().getInterfaces(),//得
到全部的接口
new InvocationHandler() {
@Override
public Object invoke(Object
proxy, Method method, Object[] args)
throws
Throwable {
// TODO Auto-generated
method stub
advice.beforeMethod
(method);//执行目标类方法前后可以执行系统功能
Object retValue =
method.invoke(target, args);
advice.endMethod
(method);
return retValue;
}
});
return proxy;
}
}
Advice.java
/**
* 系统功能的接口,我们要实现的系统功能方法都放在这
* @author Administrator
*
*/
public interface Advice {
public void beforeMethod(Method method);
public void endMethod(Method method);
}
MyAdvice.java
/**
* 系统功能实现类
* @author Administrator
*
*/
public class MyAdvice implements Advice {
//这里只是简单的模拟,只写了统计开始和结束时间的方法
long begeinTime;
@Override
public void beforeMethod(Method method) {
// TODO Auto-generated method stub
begeinTime = System.currentTimeMillis();
}
@Override
public void endMethod(Method method) {
// TODO Auto-generated method stub
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+"running time
is"+(endTime - begeinTime));
}
}
测试类:
AopFrameWorkTest.java
public class AopFrameWorkTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
InputStream ips =
AopFrameWorkTest.class.getResourceAsStream("config.properties");//取得
配置文件的输入流
Object bean = new BeanFactory(ips).getBean("csk");//根
据名字取得配置文件所对应的类;
System.out.println(bean.getClass().getName());//打印对
象名字
}
}
配置文件:
config.properties
csk=java.util.ArrayList
#csk=com.kun.day3.aopframework.ProxyFactoryBean
csk.advice=com.kun.day3.aopframework.MyAdvice
csk.target=java.util.HashSet
我们这时就可以根据配置文件来配置我们要加载来写类,如我们要使用集合
ArrayList的时候只需注释掉HashSet的配置,我们要用HashSet的使用只需在配置文
件中注释掉ArrayList的配置即可。这就是实现了模仿spring中aop的微型框架。
ps:以上讲述纯粹记事本书写的,可能存在很多不足之处和错误之处,不足之处请指出并轻碰。
- 我的第一篇博客《浅谈SSH框架原理,并模仿实现Spring中Aop框架》
- 我的第一篇hibernate框架博客
- Spring框架AOP原理
- java框架篇---spring AOP 实现原理
- Java后台框架篇--Spring的AOP实现原理
- Spring框架IOC和AOP的实现原理
- java Spring框架IOC和AOP的实现原理
- Spring框架aop实现
- SSH集成框架下真正实现Spring AOP拦截功能
- SSH集成框架下真正实现Spring AOP拦截功能
- 第一篇CSDN博客,献上我自撸的Java Web框架
- SSH:Spring框架(spring之AOP)
- Spring 的AOP--spring框架动态实现AOP
- 【spring框架】AOP的Annotation实现(上)
- 【spring框架】AOP的Annotation实现(下)
- Spring整合aspectj框架实现的aop
- Spring整合aspectj框架实现的aop
- Spring框架第一篇HelloWorld
- 回向抖动 各种动画效果
- Windows下mod_python + Apache 配置笔记
- IP分组的交付和转发 : (5) 路由器的构件
- ASCII码表
- HHVM搭建胜过ZendPHP五六倍的PHPWeb服务器(高性能PHP虚拟机Hiphop)
- 我的第一篇博客《浅谈SSH框架原理,并模仿实现Spring中Aop框架》
- Permutations 排序(有重复数)II @LeetCode
- LINQ分页和排序,skip和Take 用法
- FOR UPDATE、FOR UPDATE NOWAIT、WAIT详解
- Tomcat7.0管理用户配置
- 爱是生命的火焰
- Linux下which、whereis、locate、find 命令查找文件
- 三星Note3手势翻页/浮窗浏览使用技巧
- cocos2d-x 有关CCEditBox设置除输入框以外的可点击触发区域