当前位置:文档之家› 基于注解的Spring AOP的配置和使用

基于注解的Spring AOP的配置和使用

基于注解的Spring AOP的配置和使用
基于注解的Spring AOP的配置和使用

基于注解的Spring AOP的配置和使用

AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。 AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

我们现在做的一些非业务,如:日志、事务、安全等都会写在业务代码中(也即是说,这些非业务类横切于业务类),但这些代码往往是重复,复制——粘贴式的代码会给程序的维护带来不便,AOP就实现了把这些业务需求与系统需求分开来做。这种解决的方式也称代理机制。

先来了解一下AOP的相关概念,《Spring参考手册》中定义了以下几个AOP的重要概念,结合以上代码分析如下:

?切面(Aspect):官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”,在本例中,“切面”就是类TestAspect所关注的具体行为,例如,AServiceImpl.barA()的调用就是切面TestAspect所关注的行为之一。“切面”在ApplicationContext 中来配置。

?连接点(Joinpoint):程序执行过程中的某一行为,例如,UserService.get 的调用或者UserService.delete抛出异常等行为。

?通知(Advice):“切面”对于某个“连接点”所产生的动作,例如,TestAspect 中对com.spring.service包下所有类的方法进行日志记录的动作就是一个Advice。其中,一个“切面”可以包含多个“Advice”,例如ServiceAspect。?切入点(Pointcut):匹配连接点的断言,在AOP中通知和一个切入点表达式关联。例如,TestAspect中的所有通知所关注的连接点,都由切入点表达式execution(* com.spring.service.*.*(..))来决定。

?目标对象(Target Object):被一个或者多个切面所通知的对象。例如,AServcieImpl和BServiceImpl,当然在实际运行时,Spring AOP采用代理实现,实际AOP操作的是TargetObject的代理对象。

?AOP代理(AOP Proxy):在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理,例如,AServiceImpl;反之,采用CGLIB代理,例如,BServiceImpl。

强制使用CGLIB代理需要将 的 proxy-target-class属性设为true。

通知(Advice)类型:

?前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在

里面使用元素进行声明。例如,TestAspect中的doBefore方法。

?后置通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在里面使用元素进行声明。例如,ServiceAspect中的returnAfter方法,所以Teser中调用 UserService.delete抛出异常时,returnAfter方法仍然执行。

?返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext中在里面使用元素进行声明。

?环绕通知(Around advice):包围一个连接点的通知,类似Web中Servlet 规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在里面使用元素进行声明。例如,ServiceAspect中的around方法。

?抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。ApplicationContext中在里面使用

元素进行声明。例如,ServiceAspect中的

returnThrow方法。

注:可以将多个通知应用到一个目标对象上,即可以将多个切面织入到同一目标对象。

使用Spring AOP可以基于两种方式,一种是比较方便和强大的注解方式,另一种则是中规中矩的xml配置方式。

先说注解,使用注解配置Spring AOP总体分为两步,第一步是在xml文件中声明激活自动扫描组件功能,同时激活自动代理功能(同时在xml中添加一个UserService的普通服务层组件,来测试AOP的注解功能):

xmlns:xsi="https://www.doczj.com/doc/1418347441.html,/2001/XMLSchema-instance"

xmlns:context="https://www.doczj.com/doc/1418347441.html,/schema/context"

xmlns:aop="https://www.doczj.com/doc/1418347441.html,/schema/aop"

xsi:schemaLocation="https://www.doczj.com/doc/1418347441.html,/schema/aop https://www.doczj.com/doc/1418347441.html,/schema/aop/spring-aop-3.1.xsd

https://www.doczj.com/doc/1418347441.html,/schema/beans http://ww https://www.doczj.com/doc/1418347441.html,/schema/beans/spring-beans.xsd

https://www.doczj.com/doc/1418347441.html,/schema/context http:// https://www.doczj.com/doc/1418347441.html,/schema/context/spring-context-3.0.xsd">

第二步是为Aspect切面类添加注解:

package cn.ysh.studio.spring.aop.aspect;

import https://www.doczj.com/doc/1418347441.html,mons.logging.Log;

import https://www.doczj.com/doc/1418347441.html,mons.logging.LogFactory;

import https://www.doczj.com/doc/1418347441.html,ng.JoinPoint;

import https://www.doczj.com/doc/1418347441.html,ng.ProceedingJoinPoint;

import https://www.doczj.com/doc/1418347441.html,ng.annotation.After;

import https://www.doczj.com/doc/1418347441.html,ng.annotation.AfterReturning;

import https://www.doczj.com/doc/1418347441.html,ng.annotation.AfterThrowing;

import https://www.doczj.com/doc/1418347441.html,ng.annotation.Around;

import https://www.doczj.com/doc/1418347441.html,ng.annotation.Aspect;

import https://www.doczj.com/doc/1418347441.html,ng.annotation.Before;

import https://www.doczj.com/doc/1418347441.html,ng.annotation.Pointcut;

import https://www.doczj.com/doc/1418347441.html,ponent;

/**

* 系统服务组件Aspect切面Bean

* @author Shenghany

* @date 2013-5-28

*/

//声明这是一个组件

@Component

//声明这是一个切面Bean

@Aspect

public class ServiceAspect{

private final static Log log =LogFactory.getLog(ServiceAspec t.class);

//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点

@Pointcut("execution(* cn.ysh.studio.spring.aop.service..* (..))")

public void aspect(){}

/*

* 配置前置通知,使用在方法aspect()上注册的切入点

* 同时接受JoinPoint切入点对象,可以没有该参数

*/

@Before("aspect()")

public void before(JoinPoint joinPoint){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("before "+ joinPoint);

}

}

//配置后置通知,使用在方法aspect()上注册的切入点

@After("aspect()")

public void after(JoinPoint joinPoint){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("after "+ joinPoint);

}

}

//配置环绕通知,使用在方法aspect()上注册的切入点

@Around("aspect()")

public void around(JoinPoint joinPoint){

long start =System.currentTimeMillis();

try{

((ProceedingJoinPoint) joinPoint).proceed();

long end =System.currentTimeMillis();

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("around "+ joinPoint +"\tUs e time : "+(end - start)+" ms!");

}

}catch(Throwable e){

long end =System.currentTimeMillis();

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("around "+ joinPoint +"\tUs e time : "+(end - start)+" ms with exception : "+ e.getMessage ());

}

}

}

//配置后置返回通知,使用在方法aspect()上注册的切入点

@AfterReturning("aspect()")

public void afterReturn(JoinPoint joinPoint){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("afterReturn "+ joinPoint);

}

}

//配置抛出异常后通知,使用在方法aspect()上注册的切入点

@AfterThrowing(pointcut="aspect()", throwing="ex")

public void afterThrow(JoinPoint joinPoint,Exception ex){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("afterThrow "+ joinPoint +"\t"+ ex. getMessage());

}

}

}

测试代码:

package cn.ysh.studio.spring.aop;

import https://www.doczj.com/doc/1418347441.html,mons.logging.Log;

import https://www.doczj.com/doc/1418347441.html,mons.logging.LogFactory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationCon text;

import https://www.doczj.com/doc/1418347441.html,erService;

import https://www.doczj.com/doc/1418347441.html,er;

/**

* Spring AOP测试

* @author Shenghany

* @date 2013-5-28

*/

public class Tester{

private final static Log log =LogFactory.getLog(Tester.clas s);

public static void main(String[] args){

//启动Spring容器

ApplicationContext context =new ClassPathXmlApplicat ionContext("applicationContext.xml");

//获取service组件

UserService service =(UserService) context.getBean(" userService");

//以普通的方式调用UserService对象的三个方法

User user = service.get(1L);

service.save(user);

try{

service.delete(1L);

}catch(Exception e){

if(log.isWarnEnabled()){

log.warn("Delete user : "+ e.getMessa ge());

}

}

}

}

控制台输出如下:

INFO [spring.aop.aspect.ServiceAspect:40] before execution(User cn.y https://www.doczj.com/doc/1418347441.html,erService.get(long))

INFO [https://www.doczj.com/doc/1418347441.html,erService:19] getUser method ...

INFO [spring.aop.aspect.ServiceAspect:60] around execution(User cn.y https://www.doczj.com/doc/1418347441.html,erService.get(long))Use time :42 m s!

INFO [spring.aop.aspect.ServiceAspect:48] after execution(User cn.ys https://www.doczj.com/doc/1418347441.html,erService.get(long))

INFO [spring.aop.aspect.ServiceAspect:74] afterReturn execution(User https://www.doczj.com/doc/1418347441.html,erService.get(long))

INFO [spring.aop.aspect.ServiceAspect:40] before execution(void cn.y https://www.doczj.com/doc/1418347441.html,erService.save(User))

INFO [https://www.doczj.com/doc/1418347441.html,erService:26] saveUser method ...

INFO [spring.aop.aspect.ServiceAspect:60] around execution(void cn.y https://www.doczj.com/doc/1418347441.html,erService.save(User))Use time :2 m

s!

INFO [spring.aop.aspect.ServiceAspect:48] after execution(void cn.ys https://www.doczj.com/doc/1418347441.html,erService.save(User))

INFO [spring.aop.aspect.ServiceAspect:74] afterReturn execution(void https://www.doczj.com/doc/1418347441.html,erService.save(User))

INFO [spring.aop.aspect.ServiceAspect:40] before execution(boolean c https://www.doczj.com/doc/1418347441.html,erService.delete(long))

INFO [https://www.doczj.com/doc/1418347441.html,erService:32] delete method ...

INFO [spring.aop.aspect.ServiceAspect:65] around execution(boolean c https://www.doczj.com/doc/1418347441.html,erService.delete(long))Use time :5 ms with exception : spring aop ThrowAdvice演示

INFO [spring.aop.aspect.ServiceAspect:48] after execution(boolean cn. https://www.doczj.com/doc/1418347441.html,erService.delete(long))

INFO [spring.aop.aspect.ServiceAspect:74] afterReturn execution(bool ean https://www.doczj.com/doc/1418347441.html,erService.delete(long))

WARN [studio.spring.aop.Tester:32]Delete user :Null return value f rom advice does not match primitive return type for: public boolean c https://www.doczj.com/doc/1418347441.html,erService.delete(long) throws java. lang.Exception

可以看到,正如我们预期的那样,虽然我们并没有对UserSerivce类包括其调用方式做任何改变,但是Spring仍然拦截到了其中方法的调用,或许这正是AOP 的魔力所在。

再简单说一下xml配置方式,其实也一样简单:

xmlns:xsi="https://www.doczj.com/doc/1418347441.html,/2001/XMLSchema-instance"

xmlns:context="https://www.doczj.com/doc/1418347441.html,/schema/context"

xmlns:aop="https://www.doczj.com/doc/1418347441.html,/schema/aop"

xsi:schemaLocation="https://www.doczj.com/doc/1418347441.html,/schema/aop https://www.doczj.com/doc/1418347441.html,/schema/aop/spring-aop-3.1.xsd

https://www.doczj.com/doc/1418347441.html,/schema/beans http://ww https://www.doczj.com/doc/1418347441.html,/schema/beans/spring-beans.xsd

https://www.doczj.com/doc/1418347441.html,/schema/context http:// https://www.doczj.com/doc/1418347441.html,/schema/context/spring-context-3.0.xsd">

个人觉得不如注解灵活和强大,你可以不同意这个观点,但是不知道如下的代码会不会让你的想法有所改善:

//配置前置通知,拦截返回值为https://www.doczj.com/doc/1418347441.html,er的方法

@Before("execution(https://www.doczj.com/doc/1418347441.html,er cn.ysh.studio.s pring.aop.service..*(..))")

public void beforeReturnUser(JoinPoint joinPoint){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("beforeReturnUser "+ joinPoint);

}

//配置前置通知,拦截参数为https://www.doczj.com/doc/1418347441.html,er的方法

@Before("execution(* cn.ysh.studio.spring.aop.service..*(cn.ysh.studi https://www.doczj.com/doc/1418347441.html,er))")

public void beforeArgUser(JoinPoint joinPoint){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("beforeArgUser "+ joinPoint);

}

}

//配置前置通知,拦截含有long类型参数的方法,并将参数值注入到当前方法的形参id中

@Before("aspect()&&args(id)")

public void beforeArgId(JoinPoint joinPoint,long id){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("beforeArgId "+ joinPoint +"\tID:"+ id);

}

}

附上UserService的代码(其实很简单):

package cn.ysh.studio.spring.aop.service;

import https://www.doczj.com/doc/1418347441.html,mons.logging.Log;

import https://www.doczj.com/doc/1418347441.html,mons.logging.LogFactory;

import https://www.doczj.com/doc/1418347441.html,er;

/**

* 用户服务模型

* @author Shenghany

* @date 2013-5-28

*/

public class UserService{

private final static Log log =LogFactory.getLog(UserService. class);

public User get(long id){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("getUser method . . .");

}

return new User();

}

public void save(User user){

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("saveUser method . . .");

}

}

public boolean delete(long id)throws Exception{

if(log.isInfoEnabled()){

https://www.doczj.com/doc/1418347441.html,("delete method . . .");

throw new Exception("spring aop ThrowAdvice演示");

}

return false;

}

}

应该说学习Spring AOP有两个难点,第一点在于理解AOP的理念和相关概念,第二点在于灵活掌握和使用切入点表达式。概念的理解通常不在一朝一夕,慢慢浸泡的时间长了,自然就明白了,下面我们简单地介绍一下切入点表达式的配置规则吧。

通常情况下,表达式中使用”execution“就可以满足大部分的要求。表达式格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

?modifiers-pattern:方法的操作权限

?ret-type-pattern:返回值

?declaring-type-pattern:方法所在的包

?name-pattern:方法名

?parm-pattern:参数名

?throws-pattern:异常

其中,除ret-type-pattern和name-pattern之外,其他都是可选的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。

最后说一下通知参数

可以通过args来绑定参数,这样就可以在通知(Advice)中访问具体参数了。例如,配置如下:

expression="execution(* com.spring.service.*.*(String,..)) and ar gs(msg,..)"/>

上面的代码args(msg,..)是指将切入点方法上的第一个String类型参数添加到参数名为msg的通知的入参上,这样就可以直接使用该参数啦。

访问当前的连接点

在上面的Aspect切面Bean中已经看到了,每个通知方法第一个参数都是JoinPoint。其实,在Spring中,任何通知(Advice)方法都可以将第一个参数定义为https://www.doczj.com/doc/1418347441.html,ng.JoinPoint类型用以接受当前连接点对象。JoinPoint接口提供了一系列有用的方法,比如 g etArgs()(返回方法参数)、getThis()(返回代理对象)、getTarget()(返回目标)、getSignature()(返回正在被通知的方法相关信息)和toString()(打印出正在被通知的方法的有用信息)。

清华大学开题报告ppt

清华大学开题报告ppt 篇一:毕业论文开题报告 武汉工程大学计算机科学与工程学院 毕业论文开题报告 第 1 页共 4 页 (5)可以随时修改系统口令。 (6)灵活的数据备份、还原功能。 (7)系统最大限度地实现易安装性、易维护性和易操作性。 (8)系统运行稳定,安全可靠。 通过使用超市管理系统可以迅速提升超市的管理水平,降低经营成本,为提高效益和增强超市扩张能力,提供了有效的技术保障。本系统就是在这样的背景下提出的。另外在技术方面采用了较为先进的Java Swing技术和SQL Server XX,用来实现超市管理信息系统,包括系统登陆、基本资料、进货管理、销售管理、库存管理、系统维护、信息查询7个模块。 要求能够自觉运用数据库系统课程学习的理论知识指导软件设计;掌握信息管理系统的开发方法和步骤。整个应用系统的设计严格按照数据库设计的方法来进行,包括数据库的设计和应用程序的设计,两部分相辅相成。 数据库设计过程包含以下步骤:

需求分析:系统的目的、用户的各种需求、业务流程图、数据流程图; 概念结构设计:用E-R图来描述实体及实体间的联系; 逻辑结构设计:确定关系模式,各种约束的声明,如主码外码约束、唯一性约束、非空约束等。同时给出系统的功能模块组成图,系统各模块功能; 物理结构设计; 数据库实施; 数据库的实施阶段:数据库用SQL Server XX等创建,前端开发使用Java、.NET等实现。 通过此次课程设计提高自己独立分析问题、解决问题的能力。掌握从需求分析、数据库设计(概念设计、逻辑设计、物理设计)、编写程序、测试分析,撰写文档到最终答辩的整个过程。 参考文献: [1] 刘京华等. JAVA WEB整合开发王者归来[M].北京:清华大学出版社,XX [2] 王俊杰. 精通JAVA SCRIPT动态网页编程[M].北京:人民邮电出版社,XX [3] 李宁. Java Web编程实战宝典[M].北京:清华大学出版社,XX [4] 孙更新. Java程序开发大全[M].北京:中国铁道出

JavaScript设计模式

JavaScript设计模式的作用——提高代码的重用性,可读性,使代码更容易的维护和扩展。 1.单体模式,工厂模式,桥梁模式个人认为这个一个优秀前端必须掌握的模式,对抽象编程和接口编程都非常有好处。 2.装饰者模式和组合模式有很多相似的地方,它们都与所包装的对象实现同样的接口并且会把任何方法的调用传递给这些对象。装饰者模式和组合模式是本人描述的较吃力的两个模式,我个人其实也没用过,所以查了很多相关资料和文档,请大家海涵。 3.门面模式是个非常有意思的模式,几乎所有的JavaScript库都会用到这个模式,假如你有逆向思维或者逆向编程的经验,你会更容易理解这个模式(听起来有挑战,其实一接触你就知道这是个很简单的模式);还有配置器模式得和门面模式一块拿来说,这个模式对现有接口进行包装,合理运用可以很多程度上提高开发效率。这两个模式有相似的地方,所以一块理解的话相信都会很快上手的。 4.享元模式是一种以优化为目的的模式。 5.代理模式主要用于控制对象的访问,包括推迟对其创建需要耗用大量计算资源的类得实例化。 6.观察者模式用于对对象的状态进行观察,并且当它发生变化时能得到通知的方法。用于让对象对事件进行监听以便对其作出响应。观察者模式也被称为“订阅者模式”。 7.命令模式是对方法调用进行封装的方式,用命名模式可以对方法调用进行参数化和传递,然后在需要的时候再加以执行。 8.职责链模式用来消除请求的发送者和接收者之间的耦合。 JavaScript设计模式都有哪些? 单体(Singleton)模式:绝对是JavaScript中最基本最有用的模式。 单体在JavaScript的有多种用途,它用来划分命名空间。可以减少网页中全局变量的数量(在网页中使用全局变量有风险);可以在多人开发时避免代码的冲突(使用合理的命名空间)等等。 在中小型项目或者功能中,单体可以用作命名空间把自己的代码组织在一个全局变量名下;在稍大或者复杂的功能中,单体可以用来把相关代码组织在一起以便日后好维护。

十 大 经 典 排 序 算 法 总 结 超 详 细

前端资源收集 前端资-源收集 收集的资-源 44个 Javascript 变态题解析 javascript 变态题解析 正则表达式收集 正则表达式收集 十大经典排序算法总结(JavaScript描述)排序算法的总结 前端工具库汇总 前端工具库总结 怎么学JavaScript? 学习javascript 的学习指导 不定期更新 JavaScript技巧 javascript 编码技巧总结 H5项目常见问题汇总及解决方案 高质量的常见问题汇总 廖雪峰的 git 教-程 Git忽略规则.gitignore梳理 git 配置提交规则 全局环境,执行环境

setTimeout promises 很酷,但很多人并没有理解就在用了 promises 使用错误汇总 promises webpack 2 中文文档 输入url后的加载过程 详细解答从输入URL 到页面显示的过程 数组Array.prototype方法 介绍了数组的一些新的方法 移动端真机调试 Web 客户端存储 ESLint中文指南 webpack 2 集成ESLint react-webpack2-skeleton webpack 2 react 成功案例,包括热加载 cookie 小结 CSS定制多行省略 Ajax 知识体系大梳理 js+nodejs完成文件上传 用 webpack 实现持久化缓存 搜罗一切webpack的好文章好工具 深入理解 CSS:字体度量、line-height 和 vertical-align

原生JS中DOM节点相关API合集 正则表达式前端使用手册 聊一聊H5应用缓存-Manifest fetch进阶指南 mozilla 开发者网络 深入理解javascript原型和闭包系列JavaScript深入系列 深度长文 JavaScript数组所有API全解密你真的懂 JavaScript 的正则吗?webpack2 终极优化 文件上传那些事儿 写给前端工程师的DNS基础知识 初识weex(前端视角) - 环境搭建 前端命名规范 正则表达式 总有你要的编程书单(GitHub )JavaScript深入系列 javascript 的一些功能点 如何在小程序中调用本地接口 移动端浏览器调试方法汇总 HTML5移动开发中的input输入框类型 互联网协议入门

javascript设计模式介绍(二) 构造函数模式

本文由我司收集整编,推荐下载,如有疑问,请与我司联系 javascript 设计模式介绍(二)构造函数模式 2016/04/22 0 我们可以通过创建自定义的构造函数,从而定义自定义对象类型 的属性和方法。 例如: function Person(name.age,sex){https://www.doczj.com/doc/1418347441.html, = name;this.age = age;this.sex = sex;this.sayName = function(){ alert(https://www.doczj.com/doc/1418347441.html,); }}然后我们实例一个Personvar person1 = new Person(john ,18, 男var person1 = new Person(Rose ,17, 女 我们注意到,Person()中的代码: 没有显式地创建对象; 直接将属性和方法赋给了this 对象; 没有return 语句。 此外,还应该注意到函数名Person 使用的是大写字母P。按照惯例,构造函数始 终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。这个做 法借鉴自其他OO 语言,主要是为了区别于ECMAScript 中的其他函数;因为构造 函数本身也是函数,只不过可以用来创建对象而已。 要创建Person 的新实例,必须使用new 操作符。以这种方式调用构造函数实际 上会经历以下4 个步骤:(1) 创建一个新对象;(2) 将构造函数的作用域赋给新对象 (因此this 就指向了这个新对象);(3) 执行构造函数中的代码(为这个新对象添加 属性);(4) 返回新对象。 person1 和person2 分别保存着Person 的一个不同的实例。这两个对象都有一个constructor(构造函数)属性,该属性指向Person,如下所示。 alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true 对象的constructor 属性最初是用来标识对象类型的。但是,提到检测对象类型, 还是instanceof 操作符要更可靠一些。我们在这个例子中创建的所有对象既是Object 的实例,同时也是Person 的实例,这一点通过instanceof 操作符可以得到验 证。

javascript设计模式

【Javascript设计模式1】-单例模式 《parctical common lisp》的作者曾说,如果你需要一种模式,那一定是哪里出了问题。他所说的问题是指因为语言的天生缺陷,不得不去寻求和总结一种通用的解决方案。 不管是弱类型或强类型,静态或动态语言,命令式或说明式语言、每种语言都有天生的优缺点。一个牙买加运动员,在短跑甚至拳击方面有一些优势,在练瑜伽上就欠缺一些。 术士和暗影牧师很容易成为一个出色的辅助,而一个背着梅肯满地图飞的敌法就会略显尴尬。换到程序中, 静态语言里可能需要花很多功夫来实现装饰者,而js由于能随时往对象上面扔方法,以至于装饰者模式在js里成了鸡肋。 讲javascript设计模式的书还比较少. Pro javaScript Design Patterns.是比较经典的一本,但是它里面的例子举得比较啰嗦,所以结合我在工作中写过的代码,把我的理解总结一下。如果我的理解出现了偏差,请不吝指正。 一单例模式 单例模式的定义是产生一个类的唯一实例,但js本身是一种“无类”语言。很多讲js设计模式的文章把{}当成一个单例来使用也勉强说得通。因为js生成对象的方式有很多种,我们来看下另一种更有意义的单例。 有这样一个常见的需求,点击某个按钮的时候需要在页面弹出一个遮罩层。比如https://www.doczj.com/doc/1418347441.html,点击登录的时候. 这个生成灰色背景遮罩层的代码是很好写的.

问题是, 这个遮罩层是全局唯一的, 那么每次调用createMask都会创建一个新的div, 虽然可以在隐藏遮罩层的把它remove掉. 但显然这样做不合理. 再看下第二种方案, 在页面的一开始就创建好这个div. 然后用一个变量引用它. 这样确实在页面只会创建一个遮罩层div, 但是另外一个问题随之而来, 也许我们永远都不需要这个遮罩层, 那又浪费掉一个div, 对dom节点的任何操作都应该非常吝啬. 如果可以借助一个变量. 来判断是否已经创建过div呢? 看起来不错, 到这里的确完成了一个产生单列对象的函数. 我们再仔细看这段代码有什么不妥.

Java程序员必备的15个框架,前3个地位无可动摇!

Java程序员必备的15个框架,前3个地位无可动摇! Java 程序员方向太多,且不说移动开发、大数据、区块链、人工智能这些,大部分Java 程序员都是Java Web/后端开发。那作为一名Java Web 开发程序员必须需要熟悉哪些框架呢? 今天,栈长我给大家列举了一些通用的、必须掌握的框架,学会这些,20K+ 不是问题。 1.Spring 毫无疑问,Spring 框架现在是Java 后端框架家族里面最强大的一个,其拥有IOC 和AOP 两大利器,大大简化了软件开发复杂性。并且,Spring 现在能与所有主流开发框架集成,可谓是一个万能框架,Spring 让JAVA 开发变得更多简单。 官网: https://spring.io/projects/spring-framework 源码: https://https://www.doczj.com/doc/1418347441.html,/spring-projects/spring-framework 推荐: 2.Spring MVC

Spring MVC 是一个MVC 开源框架,用来代替Struts。它是Spring 项目里面的一个重要组成部分,能与Spring IOC 容器紧密结合,以及拥有松耦合、方便配置、代码分离等特点,让JAVA 程序员开发WEB 项目变得更加容易。 官网: https://spring.io/projects/spring-framework 源码: https://https://www.doczj.com/doc/1418347441.html,/spring-projects/spring-framework 3.Spring Boot Spring Boot 是Spring 开源组织下的一个子项目,也是Spring 组件一站式解决方案,主要是为了简化使用Spring 框架的难度,简省繁重的配置。 Spring Boot提供了各种组件的启动器(starters),开发者只要能配置好对应组件参数,Spring Boot 就会自动配置,让开发者能快速搭建依赖于Spring 组件的Java 项目。官网: https://spring.io/projects/spring-boot 源码: https://https://www.doczj.com/doc/1418347441.html,/spring-projects/spring-boot 推荐:

相关主题
文本预览
相关文档 最新文档