切面(aop)控制反转和依赖注入(IOC,DI)和spring的事务隔离和传播行为

来源:互联网 发布:培训机构网站asp源码 编辑:程序博客网 时间:2024/05/20 04:12

实现AOP,主要通过两类方式:

1.采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;

2.采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间输入有关“方面”的代码。

方式不同效果却相同,具有的特性也是相同的:

·连接点(join point):是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现AOP时,并不需要去定义一个join point。

·切入点(point cut):本质上是一个捕获连接点的结构。在AOP中,可以定义一个point cut,来捕获相关方法的调用。

·通知(advice):是point cut的执行代码,是执行“方面”的具体逻辑。

·方面(aspect):point cut和advice结合起来就是aspect,它类似于OOP中定义的一个类,但它代表的更多是对象间横向的关系。

·引入(introduce):为对象引入附加的方法或属性,从而达到修改对象结构的目的。有的AOP工具又将其称为mixin。

AOP适用于如下功能:

·安全验证(Authentication )

·缓存(Caching )

·上下文传递(Context passing )

·错误处理(Error handling )

·后期加载(Lazy loading) 

·调试(Debugging)

·记录、跟踪、优化和监测(logging, tracing, profiling and monitoring) 

·性能优化(Performance optimization) 

·持久化(Persistence)

·资源池(Resource pooling) 

·同步(Synchronization) 

·事务(Transactions)

eg:

//定义接口package com.greysh.aop.service;public interface HelloWorld {public void say();}//对应的实现为package com.greysh.aop.service.impl;import com.greysh.aop.service.HelloWorld;public class HelloWorldImpl implements HelloWorld {public void say() {System.out.println("Say HelloWorld");}}//程序调用的时候package com.greysh.aop.test;import com.greysh.aop.factory.ProxyFactory;import com.greysh.aop.service.HelloWorld;import com.greysh.aop.service.impl.HelloWorldImpl;public class TestHelloWorld {public static void main(String[] args) {HelloWorld mb = new HelloWorldImpl();HelloWorld bi = (HelloWorld) ProxyFactory.getProxy(mb);bi.say();}}//工厂package com.greysh.aop.factory;import java.lang.reflect.Proxy;import com.greysh.aop.proxy.ProxyHandler;public class ProxyFactory {public static Object getProxy(Object obj) {ProxyHandler bn = new ProxyHandler();bn.setTarget(obj);return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), bn);}}//代理和反射类package com.greysh.aop.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class ProxyHandler implements InvocationHandler {private Object target;public void setTarget(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before Helloworld");@SuppressWarnings("unused")Object result = method.invoke(target, args);System.out.println("Finish Helloworld");return null;}}//程序运行时候的结果是Before HelloworldSay HelloWorldFinish Helloworld如果不是用AOP,那么打印的结果Say HelloWorld    这5个文件构成一个最简单的AOP的DEMO  类似Struts2的拦截器  如果两个类实现同一个接口,但是用的时候用一个类代替另一个类,这就是代理模式  上述就用了代理模式   当我们调用bi.say(),其实并不是直接用HelloWorldImpl的say(),而是HelloWorld bi = (HelloWorld) ProxyFactory.getProxy(mb);这样ProxyFactory先用ProxyHandler将对象赋值,这里需要调用reflect包,重写里面的invoke方向,这里的invoke在调用的时候先执行  System.out.println("Before Helloworld");然后用反射Object result = method.invoke(target, args);  

控制反转(IOC)和依赖注入(DI)

IoC是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:<1>依赖查找(Dependency Lookup容器提供回调接口和上下文环境给组件EJBApache Avalon都使用这种方式。<2>依赖注入(Dependency Injection:组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。后者是时下最流行的IoC类型,其又有接口注入(Interface Injection),设值注入(Setter Injection)和构造子注入(Constructor Injection)三种方式。
eg:
依赖查找
public class MyBusniessObject{  private DataSource ds;  private MyCollaborator myCollaborator;   public MyBusnissObject(){Context ctx = null;try{    ctx = new InitialContext();    ds = (DataSource) ctx.lookup(“java:comp/env/dataSourceName”);    myCollaborator = (MyCollaborator) ctx.lookup(“java:comp/env/myCollaboratorName”);    }……
代码展示了基于JNDI实现的依赖查找机制,依赖查找的主要问题是,这段代码必须依赖于JNDI环境,所以它不能在应用服务器之外运行,并且如果要用别的方式取代JNDI来查找资源和协作对象,就必须把JNDI代码抽出来重构到一个策略方法中去。
依赖注入:
eg:
待注入对象
package com.senssic; public class Content {     public void BusniessContent(){       System.out.println("do business");    }       public void AnotherBusniessContent(){       System.out.println("do another business");    }}
构造子注入(Constructor Injection
public class MyBusiness {    private Content myContent;     public MyBusiness(Content content) {       myContent = content;    }       public void doBusiness(){       myContent.BusniessContent();    }       public void doAnotherBusiness(){       myContent.AnotherBusniessContent();    }}

设值注入(Setter Injection
public class MyBusiness {    private Content myContent;     public void setContent(Content content) {       myContent = content;    }       public void doBusiness(){       myContent.BusniessContent();    }       public void doAnotherBusiness(){       myContent.AnotherBusniessContent();    }}


接口注入(Interface Injection
设置接口
public interface InContent {    void createContent(Content content);}
接口注入
public class MyBusiness implements InContent{    private Content myContent;     public void createContent(Content content) {       myContent = content;    }       public void doBusniess(){       myContent.BusniessContent();    }       public void doAnotherBusniess(){       myContent.AnotherBusniessContent();    }}

spring的事务隔离级别和传播行为

Spring在TransactionDefinition接口中定义这些属性

在TransactionDefinition接口中定义了五个不同的事务隔离级别
ISOLATION_DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应 
ISOLATION_READ_UNCOMMITTED 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读
ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

在TransactionDefinition接口中定义了七个事务传播行为。
PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
原创粉丝点击