Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

实体类与数据库表对应关系通过XML配置起来,那么当数据库表字段改变时,只需将配置文件将稍微的调整即可,而在类文件中因为使用的是实体类,没有直接与数据库表关系,所以数据库的改动将影响很小。
即:间接使用对象,使用对象与原来对象通过配置文件进行配置,一如DAO与BLL,也是注入配置而成。


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

Set<UserInfo> users = dept.getUserInfos();

得不到当前部门下所有的员工信息,原因是:dept的产生是来自页面,即没有通过数据库产生,故不会有UserInfos信息,通过
deptInfo = deptInfo_manager.getDeptInfo( deptInfo.getId() ); 解决。

即:实体类要想得到数据库数据,那么别忘记一定要让此实体类与数据库连接!!!


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

?以在*.hbm.xml中指定方式为准,即使在程序中设置了主键值,在插入更新时还是采用的是配置文件中指定的主键的生成的方式,
除非主键生成方式为assigned,由程序生成,此时在程序中设置主键才有效!


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

<set name=”userPowers” inverse=”true”>
??? <key>
??????? <column name=”cid” />
??? </key>
??? <one-to-many />
</set>

inverse指定由谁控制,inverse = false,由自己控制关系。即当自己更新时,自动更新对方,而对方更新时,就不会自动更新自己。
cascade指定更新的权限,若不设置,在inverse = false时,已方任何改动都会反映到对方,若想进一步控制,可用cascade细分

cascade能设置的值有
all??????????????????????? 相当save-update加上delete
all-delete-orphan?? 相当all,并且会删除去父类失去关联的子类比如说Article.CommentList.RemoveAt(0),就会删除第一个子类
none??????????????????? 父类的操作不会关联到子类
save-update???????? 添加和更新进行级联操作
delete????????????????? 删除父类时,删除子类
delete-orphan?????? 删除父类时,删除父类没有关系的子类

<one-to-many>中,建议inverse=”true”,由“many”方来进行关联关系的维护 ,若设置one方为主方,则在删除时会自动删除子方,会删除大量数据。

<many-to-many>中,只设置其中一方inverse=”false”,或双方都不设置

参考实体类:person, son
one方:一个person对应多个son,son存在person的set中
many:一个son对应一个father
若双方都不设置inverse,都是受方
那么:?? Son为tom, Father为Davin,现在tom想改Father为Kax
son.setFather( Kax );
但:person.getSons().get( tom );仍会返回,指示Davin仍拥有tom,出现错误。
这里的关系指的是:one中一个与Set的关系???? 而many中一个与一个的关系, 将关系分成两部分,要指定一方来维护这种关系才可,否则须要手动编码来维护这种关系。


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

insertUser( User user ) C

getUser( String userId ) R
getAllUsers()
findUsersByProperty( String propertyName, Object propertyValue )

updateUser( User user ) U

deleteUser( user user ) D


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

要注意:除了在dataSource指定URL中更改的数据库名称外,还要相应修改 *.hbm.xml 的catalog指定的数据库名称

注: catalog作用: 为表名指定归属。
即:form myDB.news 当catalog=”myDB”时
可将catalog删除掉,此时默认的从从url指定的数据库名查找: from news ( 默认数据库 )
可看出:当一个项目仅用到一个数据库时删除掉catalog即可。


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

利用Hibernate时,它本身采用的是驼峰风格,若在表中指定is_index字段名,在自动生成实体类时,会将名称转成isIndex,造成数据库与实体类字段名称不一致,故为了统一,最好在数据库字段命名时采用驼峰风格


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58
int num = 0;
Long count = null;
StringBuffer queryTemp=new StringBuffer();
queryTemp.append("SELECT COUNT(*)FROM Salesrecords AS a");       
queryTemp.append(" ORDER BY a.id DESC");
count = (Long)getHibernateTemplate().find(queryTemp.toString()).listIterator().next(); 
      ##上边返回的是Long,而不是Integer
 num = count.intValue();


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

public List find(String queryString, Object value), 据传来的sql:queryString,及为sql语句中”?“指定的值value进行查询
返回结果为List
注:即使查询无数据,返回的List也不是null, 而是数据个数为0
因无论数据存不存在,总会创建一个List对象返回,可判断是否有数据的方法为:
if ( l.size > 0 ) 不用再加 ( l !=null && l.size >0 )
或( ! l.isEmpty ) 同样不用再加 l != null 判断


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58
Spring中bean的作用域


在spring2.0之前bean只有2种作用域即:singleton(单例)、non-singleton(也称 prototype), Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对 Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。

1、singleton作用域(缺省)
当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。
配置实例:

或者



2、prototype
prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。)
配置实例:

或者


3、request
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
request、session、global session使用的时候首先要在web.xml中做如下配置:

如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可:

...

org.springframework.web.context.request.RequestContextListener

...


,如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现:

..

requestContextFilter
org.springframework.web.filter.RequestContextFilter


requestContextFilter
/*

...


接着既可以配置bean的作用域了:



4、session
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例:
配置实例:
和request配置实例的前提一样,配置好web启动文件就可以如下配置:



5、global session
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。
配置实例:
和request配置实例的前提一样,配置好web启动文件就可以如下配置:



6、自定义bean装配作用域
在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和 prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope来定义,自定义自己的作用域只要实现该接口即可,下面给个实例:
我们建立一个线程的scope,该scope在表示一个线程中有效,代码如下:
publicclass MyScope implements Scope {
privatefinal ThreadLocal threadScope = new ThreadLocal() {
  protected Object initialValue(){
     returnnew HashMap();
   }
};
public Object get(String name, ObjectFactory objectFactory) {
 Map scope = (Map) threadScope.get();
 Object object = scope.get(name);
if(object==null){
   object = objectFactory.getObject();
   scope.put(name, object);
 }
return object;
}
public Object remove(String name){
 Map scope = (Map) threadScope.get();
return scope.remove(name);
}
publicvoid registerDestructionCallback(String name, Runnable callback) {
}
public String getConversationId() {
// TODO Auto-generated method stub
returnnull;
}
   }


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

Spring提供了一个 数据完整性异常,当进行insert操作时,若数据库中已存在此记录(主键相同),若某一字段在数据库中设置了不能为空,但在实际操作时却传入了null值,则就会抛出此异常,对其进行捕获,就可以得到信息,不用事先进行查询,再进行insert,直接捕获此异常并进行处理即可。
import org.springframework.dao.DataIntegrityViolationException;

try {
??????? dao.insertWords(obj);
??? } catch (DataIntegrityViolationException e) {
??? throw new Exception(“数据完整性冲突,请查看表结构是否存在问题!”);
??? }


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

在XML中配置<aop:config>时出现此错误是因为:
使用<aop:config/> 标签,需要给Spring 配置文件中引入基于xml schema 的Spring AOP 命名空间:
<beans>中要加入“xmlns:aop”的命名申明,并在“xsi:schemaLocation”中指定aop配置的schema的地址

<beans
xmlns=”http://www.springframework.org/schema/beans
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xmlns:aop=”http://www.springframework.org/schema/aop
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
??????????????? http://www.springframework.org/schema/aop
??????????????? http://www.springframework.org/schema/aop/spring-aop.xsd“>


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

Spring AspectJ方式提供了在代码中进行AOP的方式,宜于集中化管理PointCut,不用再写好代码后,在xml中配置一大串。
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件.

AspectJ语法

通配符

*? 表示任何数量的字符,除了.
.. 表示任何数量的字符包括任何数量的.
+? 描述指定类型的任何子类或者子接口???
!? 排除
||和&& 或,与

例:
java.*.Date???? 类型Date在任何直接的java子包中,如ava.util.Date和java.sql.Date
javax..*Model+? 所有javax包或者子包中以Model结尾的类型和其所有子类,如TableModel,TreeModel。
!vector???????????????????????????? 所有除了Vector的类型
Vector|| Hashtable????????????? Vector或者Hashtable类型
!public static * banking..*.*
所有的非public static 属性,在banking的包或者子包中
一,注解实现方式:

1,实现类
package com.lvjian.aop;

import java.util.Date;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect??? //指定下面的类为Aspect
public class Log {
Date date = new Date();
@Before(“execution( * *.update(..))”)???????? //任意类有update方法执行前执行logUpdate方法
??????????????????? //@Before(“execution( * *.update(..))”)? 前一个* 为update的返回类型,后一个 * 为类的名称
public void logUpdate(){
System.out.println( “begin update at ” + date.getTime() );
}

}

2,在applicationContext.xml像配置普通bean一样配置此类
<bean id=”logAspect”
</bean>

注:1,要在applicationContext.xml 加入对AspectJ的支持
<bean />
或<aop:aspectj-autoproxy/>

2, 注解有:
(1)Pointcut 当@Before(“execution( * *.update(..))”)? 多时,execution就会类同,这是切面,可定义一切面Pointcut解决。
???? @Pointcut(“execution( * *.update(..))”)
??????? public void pc(){???
??????????? System.out.println( “@Pointcut!!! “);??
????? }

???? @Before(value=”pc()”)
?????? public void logChange(){
?????????? System.out.println( “change!!! ” + date.getTime() );
}
(2)传统aop 增强类型有MethodBeforeAdvice,AfterReturningAdvice,MethodInterceptor,ThrowsAdvice等接口,对应的注解为:MethodBeforeAdvice? ??? @Before
??????? AfterReturningAdvice? ??? @AfterReturning
??????? MethodInterceptor????? ??? @Around
??????? ThrowsAdvice??????????? ??? @AfterThrowing
??????????????????????????????????????????????? @After :无论方法以何种方式结束,都会执行(类似于finally)
???????
?应用:
????
import java.util.Date;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class Log {
Date date = new Date();
@Before(“execution( * *.update(..))”)
public void logUpdate(){
System.out.println( “begin update at ” + date.getTime() );
}

@Pointcut(“execution( * *.update(..))”)
public void pc(){???
System.out.println( “@Pointcut!!! “);

}

@Before(value=”pc()”)
public void logChange(){
System.out.println( “before change!!! “? );
}

@AfterReturning(value=”pc()”)
public void AfterlogChange(){
System.out.println( “after!!! “? );
}

@Around(value=”pc()”)
public Object AroundlogChange( ProceedingJoinPoint point ) throws Throwable{
System.out.println( “around before “? );
Object re = point.proceed();
System.out.println( “around after “? );
return re;
}

@After(value=”pc()”)
public void AfterlogChange() {
System.out.println( “After ?? finally “? );
}
}
(3)注解对监听方法的操作:
1) 在形参中定义org.aspectj.lang.JoinPoint类型的参数,用些来访问方法。(注:@Around 用的是是ProceedingJoinPoint,它是org.aspectj.lang.JoinPoint的一个子类)
???
??? JoinPoint 方法有:
????? getArgs() :?? 返回方法形参
????? getThis() :?? 返回代理对象
????? getTarget() :返回目标
????? getSignature() :返回正在被通知的方法相关信息
????? toString() : 打印出正在被通知的方法的有用信息
@Before(value=”pc()”)
public void logChange( JoinPoint jp ){

System.out.println( “toString? ” + jp.toString()? );
}

2) 获取方法的参数
? getArgs() :?? 返回方法形参

? @AfterReturning(“execution( * *.admin(..))&&args(userName,..)”)?? //args与类平行
? public void AfterReturninglogAdmin( String userName ){
????? System.out.println( “after admin !!! ” + userName );
}
二,XML配置实现方式:
1, 修改xml的头部,让其支持aop命名空间。
<beans
xmlns=”http://www.springframework.org/schema/beans
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xmlns:aop=”http://www.springframework.org/schema/aop
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
??????????????? http://www.springframework.org/schema/aop
??????????????? http://www.springframework.org/schema/aop/spring-aop.xsd“>

2,在XML中配置:
<aop:config>

<aop:aspect id=”log” ref=”logXML”>
<aop:pointcut id=”update” expression=”execution( * *.XMLBefore())” />
<aop:before pointcut-ref=”update”? method=”logUpdate” />
</aop:aspect>

</aop:config>

注: 要去掉用传统方式实现的自动代理AutoProxyCreator 如:
<bean id=”autoPghroxyCreator”?>
</bean>


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

1,完成方法的增强
实现MethodBeforeAdvice,AfterReturningAdvice,MethodInterceptor,ThrowsAdvice等接口
MethodBeforeAdvice,? 在方法调用前执行 before( Method m, Object[] arg1, Object arg2)
AfterReturningAdvice, 在方法调用后执行 afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3)
MethodInterceptor,在process()前后执行,invoke(MethodInvocation mi)
ThrowsAdvice 当方法抛出异常时执行,afterThrowing(Exception ex)

public class LoginBeforeAop implements MethodBeforeAdvice,AfterReturningAdvice,MethodInterceptor {

public void before( Method m, Object[] arg1, Object arg2)
throws Throwable {
System.out.println( m.getName() + ” ” + ” before ———— ” );

}

public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println(? ” end ———— ” );
}

public Object invoke(MethodInvocation mi) throws Throwable {
//在方法执行前最早执行,在方法执行后最后执行
// TODO Auto-generated method stub
System.out.println(“method “+mi.getMethod()+” is called on “+ mi.getThis()+” with args “+(mi.getArguments()));
Object ret = mi.proceed();
System.out.println( “methodInterceptor after “);
return ret;?? //注:若没有返回ret,调用会出错
}

2,实现自己的业务类与相应的接口,抽象类等。
如: LoginDaoInf,? LoginDaoAbst,? LoginDaoImpl,????

3, 将增强与业务类对应起来

在applicationContext.xml中配置:??
//业务类
<bean id=”loginDaoImpl”></bean>
//增强类
<bean id=”loginDaoAD”></bean>

//业务类与增强类装配
<bean id=”loginDaoInf”>
//指定业务类
<property name=”target” ref = “loginDaoImpl” />
//指定增强
<property name=”interceptorNames”>
<list>
<value>loginDaoAD</value>? //注,可指定多个增强
</list>
</property>
</bean>???

注: (1) 对指定的方法应用增强。? 实现方式:增强advisor配置
上述的配置方法会对一特定类的所有方法进行增强,若想对该类指定的方法进行增强,要配置一个advisor
让它包含advice,之后在业务类与增强类装配时用advisor代替advice即可。
??? (advice 建议,advisor顾问,建议高级形式就是顾问)

配置时class为NameMatchMethodPointcutAdvisor
<bean id=”loginDaoADR”>
<property name = “mappedNames” >
<list>
<value>check*</value>
<value>show</value>
??????????????? //对类以check开头的方法及show方法应用增强,增强用advice property指定,而是哪个类则
??????????????? //要在装配时才能确定。
</list>
</property>
<property name=”advice” ref=”loginDaoAD”></property>? //可看出:advisor = adivce + poingcut
</bean>

(2) 对指定的多个类一次指定增强。??? 实现方式:改变增强与业务类的装配方式。

1) BeanNameAutoProxyCreator方式

<bean id=”loginDaoInf”>
<bean id=”AllAuto”>
??? <property name=”beanNames” >
??????? <list>??????????????????? //指定为哪些类应用增强
??????????? <value>*DaoInf</value>
??????? </list>
??? </property>
??? <property name=”interceptorNames”>
??????? <list>????????????????? //指定应用的增强,advice或advisor
??????????? <value>loginDaoAD</value>
??????? </list>
??? </property>
</bean>

(3)自动对bean应用适合的增强(查找增强时只查找advisor,不用advice,因advice不能指定方法),即当bean方法若out()执行时,就在配置文件中的所有advisor中查找,若advisor有针对out方法的配置,如:
????????????? <property name = “mappedNames” >
??????????????????????? <list>
????????????????????????????? <value>out</value>
?????????????????????? </list
?????????????? </property>
就对此方法应用增强。

这种自动增强增强的实现方式如下:
在配置文件中加入:
<bean id=”autoProxyCreator”
??>
</bean>
就自动完成方法增强的侦测!


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

AOP:
A advice 增强,指实现注入的代码
P Pointcut 切面,指对哪些类,哪些方法应用增强。


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

?所谓AOP,即面向方面编程(Aspect Oriented Programming),方面(Aspect)”它就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。它的作用更多地是关注于系统的某一方面

?? “设计模式”的触角始终在接口与抽象中大做文章,而对于对象内部则无能为力。AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的行为封装到一个可重用模块,并将其名为“Aspect”

??? Spring AOP实现AOP技术从本质上来讲,是利用了JDK提供的动态代理技术。而从实际的实现方式来看,则是利用了IoC(Inversion of Control,反转模式)机制,同时采用了AOP联盟(AOP Alliance)的通用AOP接口。首先,Spring AOP通过xml配置文件配置了pointcut,并利用Interceptor(拦截机)作为设定的触发条件。Interceptor是由用户自定义的,它相当于是AOP中的advice,但该Interceptor需要实现AOP联盟的通用AOP接口,例如 org.aopalliance.intercept.MethodInterceptor。最后定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并利用IoC机制将advice注入到接口以及实现类中。

?Spring AOP研究

Spring AOP使用纯Java实现,不需要特别的编译过程,也不需要控制类装载层次

。与JBoss AOP相同,它仍然利用了拦截器完成对方法的拦截。然而,Spring AOP

实现AOP的主要技术却主要来自于AOP联盟,如拦截器应实现

org.aopalliance.intercept.MethodInterceptor 接口,而所有advice必须实现

org.aopalliance.aop.Advice标签接口。此外,Spring实现AOP的目标也不同于其

他大部分AOP框架,它的目标不是提供及其完善的AOP实现,而是提供一个和

Spring IoC紧密整合的AOP实现,帮助解决企业应用中的常见问题。因此,Spring

AOP的功能通常是和Spring IoC容器联合使用的。AOP Advice是用普通的bean定义

语法来定义的,Advice和pointcut本身由Spring IoC 管理。这是一个重要的其他

AOP实现的区别。

3.2.3.1 切入点(pointcut)

Spring的切入点模型能够使pointcut独立于advice类型被重用。同样的pointcut

有可能接受不同的advice。将 Pointcut接口分成两个部分有利于重用类和方法的

匹配部分,并且组合细粒度的操作(如和另一个方法匹配器执行一个“并”的操

作)。

在Spring的切入点中,org.springframework.aop.Pointcut接口是重要的接口,

它用来指定通知到特定的类和方法目标。完整的接口定义如下:
public interface Pointcut
{
??? ClassFilter getClassFilter();
??? MethodMatcher getMethodMatcher();
}

ClassFilte类型也是一个接口,该接口被用来将切入点限制到一个给定的目标类

的集合。 如果matches()永远返回true,所有的目标类都将被匹配。
public interface ClassFilter
{
??? boolean matches(Class clazz);
}

MethodMatcher接口通常更加重要。完整的接口定义如下:
public interface MethodMatcher
{
??? boolean matches(Method m, Class targetClass);
??? boolean matches(Method m, Class targetClass, Object[] args);
??? boolean isRuntime();
}

matches(Method, Class) 方法被用来测试这个切入点是否匹配目标类的给定方法

。这个测试可以在AOP代理创建的时候执行,避免在所有方法调用时都需要进行测

试。如果2个参数的matches()方法对某个方法返回true,并且MethodMatcher的

isRuntime()也返回true,那么3个参数的matches()方法将在每次方法调用的时候

被调用。这使切入点能够在目标advice被执行之前立即查看传递给方法调用的参

数。由于大部分 MethodMatcher都是静态的,意味着isRuntime()方法会返回

false。此种情况下,3个参数的matches()方法永远不会被调用。

Spring AOP提供了几个实用的切入点实现,其中较为常用的是正则表达式切入点

:org.springframework.aop.support.RegexpMethodPointcut,它使用Perl 5的

正则表达式的语法。使用这个类你可以定义一个模式的列表。如果任何一个匹配

,那个切入点将被计算成 true。用法如下:
<bean id=”settersAndAbsquatulatePointcut”
???>
??? <property name=”patterns”>
??????? <list>
??????????? <value>.*get.*</value>
??????????? <value>.*absquatulate</value>
??????? </list>
??? </property>
</bean>

不过,更多情况下是直接使用RegexpMethodPointcut一个实用子类:

RegexpMethodPointcutAdvisor。它允许我们同时引用一个advice(在Spring AOP

中,advice可以是拦截器,也可以是before advice,throws advice等)。这就简

化了bean的装配,因为一个bean可以同时当作pointcut和advice,如下所示:
<bean id=”myPointcutAdvisor”

class=”org.springframework.aop.support.RegexpMethodPointcutAdvisor”>
??? <property name=”advice”>
??????? <ref local=”MyInterceptor” />
??? </property>
??? <property name=”patterns”>
??????? <list>
??????????? <value>.*save.*</value>
??????????? <value>.*do.*</value>
??????? </list>
??? </property>
</bean>

注意配置文件中的myPointcutAdvisor,在Spring AOP中,一个advisor就是一个

aspect完整的模块化表示。通过advisor,可以将pointcut和advice(在此处即为

MyInterceptor)绑定起来。

3.2.3.2 通知(advice)

Spring AOP的advice可以跨越多个被advice对象共享,或者每个被advice对象有

自己的advice。要实现advice,最简单的做法就是定义一个拦截器(Interceptor

)。它采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义为

aopalliance.jar)。要实现advice,需要实现aopalliance.jar中定义的

MethodInterceptor接口。

例如,我们定义了一个业务对象接口BusinessObject及其实现类

BusinessObjectImpl,该业务对象能够存储数据,其定义如下:
public interface BusinessObject
{
??? public void save();
}
public class BusinessObjectImpl implements BusinessObject
{
??? public void save()
??? {
???????? System.out.println(“saving domain object……”);
??? }
}

现在需要为业务对象BusinessObject的Save()方法,提供Lock机制。根据Spring

AOP的实现方式,我们可以定义一个LockInterceptor来实现MethodInterceptor接

口:
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class LockInterceptor implements MethodInterceptor
{
??? public Object invoke(MethodInvocation invocation) throws Throwable
??? {
??????? // TODO Auto-generated method stub
??????? lock();
??????? Object ret= invocation.proceed();
??????? unlock();
??????? return ret;
??? }
??? private void lock()
??? {
??????? System.out.println(“lock domain object…”);
??? }
??? private void unlock()
??? {
??????? System.out.println(“unlock domain object…”);
??? }
}

为将interceptor与具体的advice绑定起来,需要在配置文件中配置bean:
&lt;bean id=”MyInterceptor”

class=”test.aop.spring.LockInterceptor”/&gt;

3.2.3.3 AOP代理与IoC容器

由于Spring中提供了IoC容器(例如BeanFactory),因此我们可以通过Ioc机制,

利用ProxyFactoryBean来创建 AOP代理。ProxyFactoryBean和其他Spring的

FactoryBean实现一样,引入一个间接的层次。如果你定义一个名字为foo的

ProxyFactoryBean,引用foo的对象所看到的不是 ProxyFactoryBean实例本身,

而是由实现ProxyFactoryBean的类的 getObject()方法所创建的对象。这个方法

将创建一个包装了目标对象 的AOP代理。

AOP代理利用的是Java的动态代理技术,通过它就可以加载并执行AOP组件。同时

,还需要通过IoC的方式将advice注入到接口以及其实现类。以前面的业务对象

BusinessObject为例,在xml配置文件中的配置如下:
<bean id=”myAOPProxy”

class=”org.springframework.aop.framework.ProxyFactoryBean”>
??? <property name=”proxyInterfaces”>
?????? <value>test.aop.spring.BusinessObject</value>
??? </property>
??? <property name=”target”>
?????? <ref local=”impl” />
??? </property>
??? <property name=”interceptorNames”>
?????? <value>myPointcutAdvisor</value>
??? </property>
</bean>
<bean id=”impl”/>

通过上述对pointcut、advice、advisor和AOP代理的配置,我们就可以轻易地在

Spring中实现AOP,例如:
import org.springframework.context.ApplicationContext;
import

org.springframework.context.support.FileSystemXmlApplicationContext;

public class App
{
??? private BusinessObject bo = null;
??? public static void main(String[] args)
??? {
??????? ApplicationContext ctx=new FileSystemXmlApplicationContext

(“Bean.xml”);
??????? bo= (BusinessObject) ctx.getBean(“myAOPProxy”);
??????? bo.save();
??? }
}

首先,通过AOP代理获得BusinessObject对象。当调用BusinessObject对象的

save()方法时,拦截器 LockInterceptor根据RegexpMethodPointcutAdvisor配置

的pointcut和advice之间的关系,判定该方法的调用为join point,从而拦截该

方法调用,并注入advice的执行逻辑,即lock()和unlock(),最终实现了AOP。

3.2.3.4 引入(introduction)

在Spring AOP中,将introduction当作advice来处理。与一般的advice一样,

introduction advice相当于一种特殊类型的拦截通知,需要实现

IntroductionAdvisor和IntroductionInterceptor接口,而

IntroductionInterceptor接口继承自MethodInterceptor:
public interface IntroductionInterceptor extends MethodInterceptor
{
??? boolean implementsInterface(Class intf);
}

Introduction通知不能被用于任何pointcut,因为它只能作用于类层次上,而不

是方法。我们可以只用InterceptionIntroductionAdvisor来实现导入通知,它有

下面的方法:
public interface InterceptionIntroductionAdvisor extends

InterceptionAdvisor
{
??? ClassFilter getClassFilter();
??? IntroductionInterceptor getIntroductionInterceptor();
??? Class[] getInterfaces();
}

接下来,我以JBoss AOP一节中的例子来说明introduction在Spring AOP中的应用

。我们的目标仍然是为一个已有的业务对象引入第三方接口Tracing:
public interface Tracing
{
??? void enableTracing();
??? void disableTracing();
??? boolean enabled();
}

首先,我们需要一个做大量转化的IntroductionInterceptor。在这里,我们继承

org.springframework.aop.support.DelegatingIntroductionInterceptor 实现

类。当然我们可以直接实现IntroductionInterceptor接口,但是大多数情况下

DelegatingIntroductionInterceptor是最合适的。

DelegatingIntroductionInterceptor的设计是将introduction委托到真正实现

introduction 接口的接口,隐藏完成这些工作的拦截器。委托可以使用构造方法

参数设置到任何对象中;默认的委托就是自己(当无参数的构造方法被使用时)

。这样在下面的例子里,委托是DelegatingIntroductionInterceptor的子类

TracingMixin。给定一个委托(默认是自身)的

DelegatingIntroductionInterceptor实例寻找被这个委托(而不是

IntroductionInterceptor)实现的所有接口,并支持它们中任何一个导入。子类

如TracingMixi也可能调用suppressInterflace(Class intf) 方法来隐藏不应暴

露的接口。然而,不管IntroductionInterceptor 准备支持多少接口,

IntroductionAdvisor将控制哪个接口将被实际暴露。一个导入的接口将隐藏目标

的同一个接口的所有实现。

这样,TracingMixin继承DelegatingIntroductionInterceptor并自己实现接口

Tracing。父类自动选择支持introduction的Tracing,所以我们不需要指定它。

用这种方法我们可以导入任意数量的接口。
public class TracingMixin extends DelegatingIntroductionInterceptor

implements Tracing
{
??? private boolean enabled;
??? public void enableTracing ()
??? {
??????? this.enabled = true;
??? }

??? public void disableTracing ()
??? {
??????? this. enabled = false;
??? }

??? public boolean enabled()
??? {
??????? return this.enabled;
??? }
??? public Object invoke(MethodInvocation invocation) throws Throwable
??? {?????
??????? return super.invoke(invocation);
??? }
}

通常不要需要改写invoke()方法:实现DelegatingIntroductionInterceptor就足

够了,如果是引入的方法,DelegatingIntroductionInterceptor实现会调用委托

方法, 否则继续沿着连接点处理。

所需的introduction advisor是很简单的。只需保存一个独立的TracingMixin实

例,并指定导入的接口,在这里就是Tracing。此时,TracingMixin没有相关配置

,所以我们简单地使用new来创建它。

public class TracingMixinAdvisor extends DefaultIntroductionAdvisor
{
??? public TracingMixinAdvisor() {
??????? super(new TracingMixin(),Tracing.class);
??? }
}

我们可以非常简单地使用这个advisor。它不需要任何配置。(但是,有一点是必

要的:就是不可能在没有IntroductionAdvisor 的情况下使用

IntroductionInterceptor。) 和引入一样,通常 advisor必须是针对每个实例

的,并且是有状态的。我们会有不同的TracingMixinAdvisor。每个被通知对象,

会有不同的 TracingMixin。advisor组成了被通知对象的状态的一部分。

在Spring中,Spring AOP的核心API已经基本稳定了。和Spring的其它部分一样,

AOP框架是模块化的,在保留基础设计的同时提供扩展。在Spring 1.1到1.2阶段

有很多地方可能会有所提高,但是这些地方也保留了向后兼容性。它们是:

(一)性能的提高:AOP代理的创建由工厂通过策略接口处理。因此能够支持额外

的AOP 代理类型而不影响用户代码或核心实现。
(二)更具表达力的pointcut:Spring目前提供了一个具有表达力的切入点接口

,同时添加了更多的切入点实现。Spring正在考虑提供一个简单但具有强大表达

式语言的实现。


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

这两个概念基本上是一个设计层的概念,主要讲的就是怎么去分离关注,用面向

对象的话说,就是怎么把职责进行分离。而这两个模式,我个人认为都有一个共

同点,就是变以前的主动为被动,而我认为,这种改变可能也是将来面向对象发

展的一个趋势。

首先说说什么叫主动。写过面向对象程序的人都知道,面向对象与面向过程的区

别就是,面向对象是由一大堆对象组成的,对象通过协作完成面向过程中的任务

。假设现在有对象A和B,那么当A需要使用B中的方法时,那么在A内部,就会有有

一个对B方法的调用,这种调用就称为主动调用。代码大概会如下:

public class A{

B b;

public void methodA(){

b.methodB();

}

}

这里为了下文解释方便,我增加了一个调用点的定义,调用点就是调用发生的地

方。也就是上面

b.methodB()中的b。

理解了什么叫主动之后,我想就先介绍什么叫IoC。IoC的全称这里就不说了,他

的字面意思就是控制反转。在上面的代码当中,由于A调用了B的方法,因此就形

成了一个A对B的依赖,这本身并没有什么问题。但是OO的思想是希望我们基于接

口编程,而不是基于实现编程。因此,系统设计将不止是原有的 A,B,而需要变

成IA,IB,A,B,其中IA,IB是接口,A,B是对应的实现类,然后为了使得A中现

在对B的实现依赖变成对接口的依赖,代码应该变成这样。

public class A implements IA{

IB b;

public void methodA(){

b.methodB();

}

}

这里虽然我们是基于接口编程了,但大家知道,在这中间,我们需要有一个步骤

把b指向一个IB的实现类B,这个怎么做,就是IoC要做的事情,这里就不细说了。

但简单来说,没有IoC,我们可能需要在A中通过某种方法去获取一个B的实例,但

有了IoC,她就能在A不参与的情况下,给我们一个B的实例,所以,IoC要做的就

是在调用点上从原来的主动生成一个调用点,变成被动的接受一个调用点。

接着就是AOP,全称也不说了,字面意思就是面向方面编程。举一个最普遍的例子

,就是如果我们代码需要做日志的话,那么在没有AOP的时候,我们的代码可能就

是这样:

public class A{

public void methodA(){

do log;

b.methodB();

}

}

这里methodA()中的做日志并不是方法本身的逻辑功能,而是一个附属功能,因此

,我们需要把它分离出去。怎么分离,就是AOP要做的事情,简单来说,就是系统

在调用者不知情的情况下,为我们的类A增加了一个代理类,她把我们的类A包装

了起来,像这样:

public class AP extends A{

A a;

public void methodA(){

do log;

a.methodA():

}

}

public class A{

public void methodA(){

b.methodB();

}

}

于是,当我们以为自己在调用A的methodA()方法时,实际调用的将是AP中的

methodA(),于是就可以把做日志的功能从原有的 methodA()中分离了出去。所以

,AOP要做的就是在用户不知道的情况下,将我们的调用点包裹了起来,从而把原

来的功能进行了分离。


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

原因:getHibernateTemple作用:在DAO类操作实体类时应用,因对数据库进行操作,故要获得在applicationContext.xml数据库的配置信息,如:当前实体类*.hbm.xml信息 但getHibernateTemple位于DAO中,不能自己获得此重要信息,要通过DAO来获得。
获得方式:DAO 继承HibernateDaoSupport类,在applicationContext中为此DAO配置sessionfactory属性
<bean id=”consultingDao”
parent=”dao”>
<property name=”sessionFactory” ref=”sessionFactory” />? //sessionFactory当指定Spring接管hibernate时自动配置
</bean>


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

因DAO类要注入SessionFactory才能使得HibernateTemple运行,故要手动获得配置文件,用配置文件中的DAO来完成对象的建立,而不
是用new来创建DAO类来进行数据库的操作。

String [] confile = {
??????? “WebRoot\\WEB-INF\\applicationContext-db.xml”,
??????? “WebRoot\\WEB-INF\\applicationContext-dao.xml”,
??????? “WebRoot\\WEB-INF\\applicationContext-service.xml”
};
ApplicationContext ac = new FileSystemXmlApplicationContext(confile );
ManageDAOInf mi = (ManageDAOInf) ac.getBean( “manageInf” );


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

两种创建方法:
1,ClassPathXmlApplicationContext

ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationContext.xml”);

(1)默认路径:ClassPathXmlApplicationContext 既然名为ClassPath,那么它的相对路径就是ClassPath,即:src/
故用applicationContext.xml找的就是src下的”applicationContext.xml文件!!!
(2)绝对路径:前加前缀:file:
??? ApplicationContext ac = new ClassPathXmlApplicationContext( “file:E:\\workspace\\lj\\WebRoot\\WEB-INF\\applicationContext-db.xml” )

2,FileSystemXmlApplicationContext
ApplicationContext ac = new FileSystemXmlApplicationContext(“applicationContext.xml”);
默认路径:若写相对路径,相对的是工程根目录。即:lj/applicationContext.xml, 此xml文件与src文件夹平行。
? 可直接写绝对路径,加不加file都可以。

几种前缀:file:指定绝对路径?????????? ClassPath:指定src/路径?? (1默认,2要加才可)

注:(1)在类中进行手动注入时,注意的是路径要参考源工程的目录结构,而不是发布后的目录结果。
(2)读取多个配置文件:
? String [] confile = {
??????? “WebRoot\\WEB-INF\\applicationContext-db.xml”,
??????? “WebRoot\\WEB-INF\\applicationContext-dao.xml”,
??????? “WebRoot\\WEB-INF\\applicationContext-service.xml”
};
ApplicationContext ac = new FileSystemXmlApplicationContext(confile );