1、EL(SPEL) php
ELcss
1.概述;
EL是JSP内置的表达式语言,用以访问页面的上下文以及不一样做用域中的对象 ,
取得对象属性的值,或执行简单的运算或判断操做。EL在获得某个数据时,会自动进行数据类型的转换。
使用EL表达式输出数据时,若是有则输出数据,若是为null则什么也不输出。
2.语法:
a.EL表达式老是放在{}中,并且前边有一个$做为前缀:${}
b.获取对象的属性值能够直接经过“对象.属性名”:${user.name};
注意:这里的属性名是get和set方法对应的属性值,并非对象中的变量名。
c.获取对象的属性也能够经过“对象[“属性名”]”:${user["name"]}
d.获取Map中属性时能够以直接经过属性的key:${map.key},${map[key]}
e.在指定域中获取属性:
在EL表达式中若是咱们直接使用属性名如:${user},它将会在四个域中由小到大依次查找。
顺序:pageScope、requestScope、sessionScope、applicationScope。
也能够指定从哪一个域中获取:
${ pageScope .user }:当前页面
${requestScope.user}:当前请求
${sessionScope.user}:当前会话
${sessionScope.user}:当前应用
3.EL中包含11个隐含对象,这些对象能够在EL表达式中直接使用:
a.pageContext,和JSP中的pageContext功能同样java
b.请求域:pageScope/requestScope/sessionScope/applicationScope
c.请求参数,参数对象主要用于获取get或post请求中的参数:
param:获取指定的请求参数,${param.username}
paramValues:获取请求参数数组,如:${paramValues.sport[1]}
d.其余:header/headerValues/initParam/cookie正则表达式
4.EL支持数学运算和逻辑运算:
a.加减乘除:${17+5} => 22
b.取余%或mod:${17%5} => 2
c.比较运算符>,<,==,!=,<=,>=,eq,ne,lt,gt,le,ge:${3>5}或${3 gt 5} =>false
d.逻辑比较 &&或and,!或not,||或or,empty:${!true} => false
spring
SPEL
1.Spring框架的表达式语言(简称SpEL):是一个支持运行时查询和操做对象图的强大的表达式语言。
SpEL 为 bean 的属性进行动态赋值提供了便利.
2.语法:SpEL 使用 #{…} 做为定界符,全部在大框号中的字符都将被认为是 SpEL。
3.运用范围:
a. 对 bean 进行引用,调用属性值:#{book.name}
b.调用方法以及引用对象中的属性
引用方法:#{dog.run()},引用静态方法:#{T(java.lang.Math).PI}
引用对象的属性:#{user.name}
c.计算表达式的值
加减乘除:#{counter.total + 40},#{T(java.lang.Math).PI * 2}
加号做为字符串链接符:#{user.name + ' ' + user.address}
比较运算符(>,<,=,>=,<=,==,lt,gt,eq,le,ge):
#{counter.total == 100},#{counter.total le 1000}
if-else条件判断,三元运算符:
#{user.name=='Tom' ? 'Jess'}shell
d.正则表达式的匹配(matches)
#{user.name matches '^[a-zA-Z0-9_-]{4,16}$'}
e.字面量的表示:
#{5},#{89.7},#{1e4},#{false}
可以使用单/双引号做为字符串表达符号:#{'Chuck'},#{"Chuck"}
设计模式
2、Decorator:数组
1.Decorator 设计模式的特色:安全
Decorator 设计模式正如毛胚房的装修,不会改变原毛胚房的基本框架,只是增长新的外观、功能等,且随着时间的推移,能够不断的实施装修工程:增长新的家具、根据心情换换新鲜的墙纸等等。在面向对象的程序设计中,扩展系统的原有功能也能够采用继承、组合的方式。继承也不会改变毛胚房(父类),可是因为装修工程的复杂和不少不可预测的改变,好比不一样墙纸和地板样式的组合数量简直没法想一想,难道咱们要为每一种组合都定义一个子类吗?显然这是不现实的,即经过继承的方式来应对将来的功能和外观改变一般是吃力不讨好的事情。组合的方式也不可取,由于这要求不断的修改父类的结构,至关于对毛胚房大动干戈,房屋的可维护性和可靠性就大大下降了。服务器
让咱们回顾一下设计模式的重要原则:Classes should be open for extenstion, but closed for modification。Decorator 设计模式很好的诠释了这个原则。
2.CDI 对 Decorator 设计模式的支持:
Decorator 设计模式虽然下降了需求变动对软件开发的影响,可是经过层层包装,即层层 new 操做建立对象的方式不够优雅。CDI 容器能够管理组件的生命周期,在大部分状况下咱们无须经过 new 操做建立所须要的对象。CDI 中的 Decorator/Delegate 注解很大程度上简化了 Decorator 设计模式的代码编写量,好比实现上面相同的功能,借助于 CDI,就无须 RoomDecorator 这个抽象类了,全部的 Decorator 类直接实现 Room 接口并使用注解声明为 Decorator 便可
3.总结:
Decorator 设计模式简单而精巧,它实际上是 Unix 哲学的体现:每个应用程序都尽力作好本身,而后经过应用程序之间的协做完成更复杂的任务,正如 shell 的管道符的做用。从复杂应用程序框架设计的角度看,Decorator 设计模式也下降了模块之间的耦合度,而 CDI 更进了一步,借助于容器和类型安全的组件模型,简化了 Decorator 模式的应用,同时消除了某些潜在的运行时异常,也就是说,CDI 之上的 Decorator 设计模式可以帮助构建更加安全的复杂应用。
3、Interceptor
1.拦截器综述:
拦截器的功能是定义在Java拦截器规范。
拦截器规范定义了三种拦截点:
在容器的生命周期中进行拦截
public class DependencyInjectionInterceptor { @PostConstruct public void injectDependencies(InvocationContext ctx) { ... } }
EJB超时时使用的拦截器
public class TimeoutInterceptor { @AroundTimeout public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
在业务上,对某一个Bean的方法进行拦截
public class TransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
2.拦截器绑定(Interceptor bindings)
假设咱们想要申明一些bean的事务。咱们先要的是一个拦截器绑定类型来指定哪些bean咱们要申明.
首先定义一个注解
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Transactional {}
2.拦截器实现(Implementing interceptors)
咱们实际上要实现提供了这种事务管理方面的拦截器,因此咱们须要作的是建立一个标准的拦截,并配上@Interceptor和@transactional注解.
@Transactional @Interceptor public class TransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
拦截器能够利用依赖注入:
@Transactional @Interceptor public class TransactionInterceptor { @Resource UserTransaction transaction; @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
多个拦截器可使用相同的拦截器绑定类型。
3.启用拦截器(Enabling interceptors)
默认状况下,全部拦截器被禁用.要使用拦截器.须要在bean.xml中进行配置,以启用.从CDI 1.1起拦截器可使用@Priority注释为整个应用程序启用。
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"> <interceptors> <class>org.mycompany.myapp.TransactionInterceptor</class> </interceptors> </beans>
这样有2个好处:
固然也能够配置启用多个拦截器
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"> <interceptors> <class>org.mycompany.myapp.SecurityInterceptor</class> <class>org.mycompany.myapp.TransactionInterceptor</class> </interceptors> </beans>
拦截器毕竟比较重要,不推荐使用@Priority启用.
在CDI中,XML配置的优先级高于@Priority.
4.Interceptor bindings with members(拦截器注解属性)
假设咱们想要添加一些额外的信息给咱们的@transactional注解:
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Transactional { boolean requiresNew() default false; }
CDI将使用requiresNew的值选择两个不一样的拦截器,TransactionInterceptor和RequiresNewTransactionInterceptor
下面是requiresNew为true的拦截器
@Transactional(requiresNew = true) @Interceptor public class RequiresNewTransactionInterceptor { @AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... } }
以下使用:
@Transactional(requiresNew = true) public class ShoppingCart { ... }
可是若是咱们只有一个拦截器,咱们但愿容器拦截器绑定时忽略requiresNew的值,也许这些信息只用于拦截器实现。咱们可使用@Nonbinding注释:
@InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Secure { @Nonbinding String[] rolesAllowed() default {}; }
5.Multiple interceptor binding annotations(多重拦截器绑定注解)
一般咱们使用拦截器绑定的组合类型绑定多个拦截器bean。例如,下面的声明将用于绑定TransactionInterceptor和SecurityInterceptor这2个拦截器到ShoppingCart.
@Secure(rolesAllowed="admin") @Transactional public class ShoppingCart { ... }
然而,在很是复杂的状况下,一个拦截器自己可能指定拦截器绑定类型:
@Transactional @Secure @Interceptor public class TransactionalSecureInterceptor { ... }
那么这个拦截器能够绑定到checkout() 方法,如下任何组合均可使用:
public class ShoppingCart { @Transactional @Secure public void checkout() { ... } }
@Secure public class ShoppingCart { @Transactional public void checkout() { ... } }
@Transactional public class ShoppingCart { @Secure public void checkout() { ... } }
@Transactional @Secure public class ShoppingCart { public void checkout() { ... } }
6. Interceptor binding type inheritance(拦截器绑定类型继承)
Java语言支持注解的一个限制就是缺少注解继承.注解应该重用内置已有的.就如同下面这段代码表达的意思
//实际没这写法 public @interface Action extends Transactional, Secure { ... }
幸运的是,CDI围绕Java没有的这个特性开展了一些工做.
咱们会标注一个拦截器绑定类型,其有其余拦截器的绑定类型,(称为元注解)
表述起来有点费劲,就如同下面代码这样.
@Transactional @Secure @InterceptorBinding @Target(TYPE) @Retention(RUNTIME) public @interface Action { ... }
如今任何Bean绑定 Action这个注解 ,其实就是绑定到了@Transactional @Secure.(就是拦截器TransactionInterceptor和拦截器SecurityInterceptor). (甚至TransactionalSecureInterceptor,若是它存在.)
7.Use of @Interceptors(同时用多个拦截器)
这个注解@Interceptors是拦截器规范定义的,cdi是支持的<使用托管bean和EJB规范>.以下:
@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class}) public class ShoppingCart { public void checkout() { ... } }
但缺点也很明显,不推荐使用.缺点以下:
所以仍是使用上面CDI的使用方式比较好.
4、Producer
CDI是为解耦而生.如Spring主要用途是AOP.IOC(DI),而CDI除了DI外,AOP功能也是有的.从实际使用上来看,CDI比Spring功能更丰富,更灵活,其代价也是有的,学习成本相对spring较高.
1.CDI致力于松耦合,强类型.
实现松散耦合的三种方式:
这些技术使客户端和服务器的松散耦合服务。客户端再也不是紧密地绑定到一个接口的一个实现,也不须要管理生命周期实现。这种方法容许有状态的对象看成服务交互。松散耦合使系统更具活力。在之前,框架老是牺牲了类型安全(尤为是经过使用XML描述符,Spring2.5)。
CDI提供了三个额外的重要措施,进一步松耦合:
第二个CDI是强类型的.不管是依赖关系的信息,拦截器,修饰符的Bean,以及CDI event的生产者,消费者等的信息所有都是类型安全的.由编译器进行验证.
CDI是确确实实没String标识符,如xml配置什么的.好比Spring2.5用XML配置,其实都是字符串,以及"约定大于配置"的概念.在CDI里是没有的.CDI框架不是隐藏,而是没有.
这种方法的最明显好处就是任何IDE均可以提供自动完成,验证以及最重要的重构!(了解JPA的,能够对比安全类型的查询和JPQL.若是重构代码JPQL是很是麻烦的).
还有个好处就是你在识别不一样的对象,事件,拦截器能够经过注解而不是字符串名字,这样你能够提高代码质量.
CDI鼓励开发使用注解.如
@Asynchronous,
@Secure,
@Updated,
而不是使用复合名称,
asyncPaymentProcessor,
SecurityInterceptor
DocumentUpdatedEvent.
这也符合代码大全里的一些概念.只不过不用费尽心思考虑命名了,这样更简洁高效.
注释是可重用的。他们帮助描述系统的不一样部分的共同特质。他们帮助咱们分类和理解代码。他们帮助咱们应对常见问题的经常使用方法。他们使咱们的代码更简洁高效.
2.高级功能Producer methods
A:Producer methods的Scope
Producer methods的默认范围是@Dependent.
从上面代码咱们能够思考一种场景,那就是一个用户会话中有多个PaymentStrategy对象的实例.若是想改变,咱们能够在Producer方法上添加一个@SessionSciped注解.
如今,若是一个用户调用了这个Producer methods,那么返回的这个PaymentStrategy对象的实例将绑定到会话的上下文.Producer methods不会再实例化另外一个出来.
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy() { ... }
注意:Producer methods不继承声明此Producer methods的Bean的Scope.
其实这里有2个不一样的Bean:Producer methods(至关于一个Bean)以及声明这个生产方法的Bean.
B: Injection into producer methods
在Producer methods一开始的实例有一个潜在的问题
CreditCardPaymentStrategy 的实现使用 Java new 运算符来实例化。
private PaymentStrategyType paymentStrategy;
而producer methods应该理解为一个独立的Bean,而paymentStrategy是从Preferences 中用new实例化的.因此咱们应该使用下面这种方式来使用producer methods方法.
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps, CheckPaymentStrategy cps, PayPalPaymentStrategy ppps) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; case PAYPAL: return ppps; default: return null; } }
这里会有问题,若是CreditCardPaymentStrategy 是一个@RequestScope,那这里必然是要发生错误的.由于注入的CreditCardPaymentStrategy Bean实例是request,在@SessionScoped使用前容器就会进行销毁.那么就出错了.
C:Use of @New with producer methods<不推荐>
Consider the following producer method:
@Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps, @New CheckPaymentStrategy cps, @New PayPalPaymentStrategy ppps) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; case PAYPAL: return ppps; default: return null; } }
这将会建立一个新的CreditCardPaymentStrategy依赖实例,传递到生产方法,依赖对象不会被摧毁,直到会话结束。
在CDI 1.1 @New限定符被弃用。CDI鼓励应用程序注入@Dependent范围bean。
D:Disposer methods
一些Procucer methods返回的对象须要显式的破坏。例如,有人须要关闭这个JDBC链接:
@Produces @RequestScoped Connection connect(User user) { return createConnection(user.getId(), user.getPassword()); }
而在一个相同的类中,disposer method能够进行匹配.
void close(@Disposes Connection connection) { connection.close(); }
说明:在同一个类中,disposer method能够进行匹配类型为Connection 的Procucer methods,从而在 Procucer methods周期结束后进行jdbc的连接关闭.
以下面这个:
import javax.enterprise.context.RequestScoped; import javax.enterprise.inject.Disposes; import javax.enterprise.inject.Produces; import javax.enterprise.inject.spi.InjectionPoint; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Resources { @PersistenceUnit private EntityManagerFactory entityManagerFactory; @Produces @RequestScoped protected EntityManager createEntityManager() { return entityManagerFactory.createEntityManager(); } //参数必须对应上面方法的返回值 protected void closeEntityManager(@Disposes EntityManager entityManager) { if ( entityManager.isOpen() ) { entityManager.close(); } } }
结束.