面向切面编程认识及案例

面向切面编程


1 代理机制(Proxy)即通过代理对象访问目标对象。
  
  目的:在不改变目标对象源码的基础上,扩展目标对象的功能 。


2 java的三种代理模式:
  
   静态代理,动态代理,CGLIB Javassist等代理类库。
   
静态代理: 代理类由开发人员实现,在程序编译时确定代理对象与目标对象的关系。


静态代理例子


public interface IUserDao {


/**
* 通过用户名获取用户信息
* @param username 用户名
* @return
*/
User findByUsername(String username);

void  save(User user);
}
/**
   * dao层目标类
   * @author Administrator
   *
   */
@Repository
public class UserDaoImpl implements IUserDao {


@Override
public User findByUsername(String username) {
        //long sta=System.currentTimeMillis();
        System.out.println("IuserDao的findByUsername方法执行");
        //int i=1/0;
       // long end=System.currentTimeMillis();
        //System.out.println("IuserDao的login方法执行的时间:"+(end-sta));
return null;
}


@Override
public void save(User user) {

//long sta=System.currentTimeMillis();
        System.out.println("IuserDao的save方法执行");
        //long end=System.currentTimeMillis();
      //  System.out.println("IuserDao的save方法执行的时间:"+(end-sta));

}


}
 /**
    *  dao层代理类
    * @author Administrator
    *
    */
public class UserDaoProxyImpl implements IUserDao{


private IUserDao sgerten;
   
public UserDaoProxyImpl(IUserDao sgerten) {
this.sgerten = sgerten;
}


@Override
public User findByUsername(String username) {
long sta=System.currentTimeMillis();
User user=sgerten.findByUsername(username);
        long end=System.currentTimeMillis();
        System.out.println("IuserDao的login方法执行的时间:"+(end-sta));
        
        
return user;
}


@Override
public void save(User user) {

long sta=System.currentTimeMillis();
         sgerten.save(user);
        long end=System.currentTimeMillis();
        System.out.println("IuserDao的save方法执行的时间:"+(end-sta));
}


}


/**
   2017年10月9日
    createby:石烁
   类描述:dao类
*/
public class Test {
    public static void main(String[] args) {
UserDaoImpl segerten=new UserDaoImpl();
UserDaoProxyImpl proxy=new UserDaoProxyImpl(segerten);
proxy.findByUsername("ammin");
proxy.save(null);

}
}


优势:在不改变目标对象源码的基础上,扩展目标对象的功能
 
弊端:1、需要为每一个目标类提供一个代理类,开发人员就编写大量的代理类,不便于项目开发和维护,大大降低了程序的开发效率


      2、静态代理需要实现接口中所有的方法,在这些方法中加入共同实现额外服务的代码,不便于项目开发和维护,大大降低了程序的开发效率


 
动态代理:代理类由jvm运行时产生,在程序运行时确定代理对象与目标对象的关系。


通过反射机制、java.lang.reflect.Proxy类、java.lang.reflect.InvocationHandler接口共同完成动态代理的实现。


1、Proxy类提供一些类方法用于创建代理对象


static Object newProxyInstance(ClassLoader loader, Class<?> [] interfaces, InvocationHandler handler);
第一个参数ClassLoader类型,目标类和代理需要使用共同的类加载
第二个参数Class类型数组,目标类和代理类需要实现相同的接口
第三个参数InvocationHandler接口类型,代理类提供额外服务以及要调用的目标对象的方法


2、InvocationHandler接口:代理对象需要实现的额外服务以及需要调用的目标方法都在该接口中实现


Object invoke(Object proxy, Method method, Object[] args) : 代理对象需要调用该方法实现提供额外服务
第一个参数Object类型 : 调用该方法代理对象
第二个参数Method类型 : 用于封装目标对象的目标方法
第三个参数Object数组 : 用于封装目标方法需要的实参


动态代理例子
public interface IUserDao {


/**
* 通过用户名获取用户信息
* @param username 用户名
* @return
*/
User findByUsername(String username);

void  save(User user);
}
/**
   * dao层目标类
   * @author Administrator
   *
   */
@Repository
public class UserDaoImpl implements IUserDao {


@Override
public User findByUsername(String username) {
        //long sta=System.currentTimeMillis();
        System.out.println("IuserDao的findByUsername方法执行");
        //int i=1/0;
       // long end=System.currentTimeMillis();
        //System.out.println("IuserDao的login方法执行的时间:"+(end-sta));
return null;
}


@Override
public void save(User user) {

//long sta=System.currentTimeMillis();
        System.out.println("IuserDao的save方法执行");
        //long end=System.currentTimeMillis();
      //  System.out.println("IuserDao的save方法执行的时间:"+(end-sta));

}




}
/**
 * InvocationHandler接口
 * 
 * @author Administrator
 *
 */
public class TimmerHannder implements InvocationHandler {


private Object target;

public TimmerHannder(Object target) {

this.target = target;
}


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

long start =System.currentTimeMillis();

Object result=method.invoke(target, args);

long end =System.currentTimeMillis();
System.out.println(method.getName()+"的执行时间"+(end-start)+"毫秒");
return result;
}


}
public class TestDeyProxy  {


 public static void main(String[] args) {
 //创建目标对象
 UserDaoImpl target =new UserDaoImpl();
 //获取目标对象的类加载器
 ClassLoader loader=target.getClass().getClassLoader();
 //获取目标对象的实现接口
 Class<?>[] interfaces=target.getClass().getInterfaces();
//创建提供服务的hannder对象
TimmerHannder hannder=new TimmerHannder(target);
//创建代理对象
IUserDao proxy=(IUserDao) Proxy.newProxyInstance(loader, interfaces, hannder);

proxy.findByUsername("admin");
 
proxy.save(null);
 
}
}


总结:代理类和类都是基于接口实现的,代理类和目标类基于相同接口。

AOP概念
 
 1 什么叫AOP?


   将原来分散到核心业务逻辑中的重复代码提取出来,利用代理机制在运行将这些横切的业务代码动态切入到核心业务逻辑中,这就是面向切面编程。

 2  什么是通知


   将原来分散到核心业务逻辑中的重复代码提取出来,将其封装到一个方法,那么这个方法就称为通知,通知在运行时需要利用动态代理机制将其切入到
    
   核心业务逻辑中。

3  通知的类型


前置通知(before advice): 目标方法执行之前需要执行的通知


返回后通知(returning advice):目标方法正常执行结束后要执行的通知


异常后通知(throwing advice):目标方法抛出异常结束后要执行的通知


后置通知(final advice):目标方法结束总是要执行的通知


环绕通知(around advice):目标方法执行前后都要执行的通知


4  什么是连接点(join point)


通知可以应用到哪些位置,aop支持的连接点有:构造方法、代码块、成员变量、成员方法,但是spring只支持成员方法作为连接点

5  什么是切入点(point cut)


通知要应用到哪些位置。

6  什么是切面(aspect)?


  通知和切入点的组合。

7  通过apsectj的表达式定义切入点:


      常用的表达式 :


execution([方法的修饰符] 返回值类型 完整类型名.方法名([参数类型,……]))

Aop使用案例


基于schema的aop实现

public interface IUserDao {


/**
* 通过用户名获取用户信息
* @param username 用户名
* @return
*/
User findByUsername(String username);

void  save(User user);
}
/**
   * dao层目标类
   * @author Administrator
   *
   */
@Repository
public class UserDaoImpl implements IUserDao {


@Override
public User findByUsername(String username) {
        //long sta=System.currentTimeMillis();
        System.out.println("IuserDao的findByUsername方法执行");
        //int i=1/0;
       // long end=System.currentTimeMillis();
        //System.out.println("IuserDao的login方法执行的时间:"+(end-sta));
return null;
}


@Override
public void save(User user) {

//long sta=System.currentTimeMillis();
        System.out.println("IuserDao的save方法执行");
        //long end=System.currentTimeMillis();
      //  System.out.println("IuserDao的save方法执行的时间:"+(end-sta));

}

}


public class AdviceSupport {
   
     /**
      * 前置通知
      * @param jp
      */
public void before(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"前置通知");
}
      /**
       * 返回后通知
       * @param jp
       */

public void returnAfter(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"方法正常执行结束");
}
/**
* 异常抛出通知
* @param jp
* @param t
*/

public void thowingAfter(JoinPoint jp,Throwable t){
System.out.println(jp.getSignature().getName()+"异常信息通知"+t.getMessage());
}
/**
* 最终通知
* @param jp
*/

public void fainlly(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"方法正常执行结束最终通知");
}
/**
* 环绕通知
* @param jp
* @return
* @throws Throwable
*/
public  Object around(ProceedingJoinPoint jp) throws Throwable{

long begin=System.currentTimeMillis();

Object object=jp.proceed();
long end=System.currentTimeMillis();

System.out.println(jp.getSignature().getName()+"执行时间"+(end-begin)+"毫秒");
return object;
}
}


/**
 *
 *测试类
 *
 */


public class TestAop {


public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

IUserDao userDao = context.getBean(IUserDao.class);

userDao.save(null);

userDao.findByUsername("");
}


}
xml配置文件信息


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
                   http://www.springframework.org/schema/beans/spring-beans.xsd
                   http://www.springframework.org/schema/context
                   http://www.springframework.org/schema/context/spring-context.xsd
                   http://www.springframework.org/schema/aop
                    http://www.springframework.org/schema/aop/spring-aop.xsd">
  
<context:component-scan base-package="com.zhidisort.**.impl"/>

<!-- 将通知支持类纳入到spring的IoC容器 -->
<bean class="com.zhidisort.advice.AdviceSupport" id="adviceSupport"/>

<aop:config>

<aop:aspect id="apsect1" ref="adviceSupport">
<aop:pointcut expression="execution(* com.zhidisort.dao.impl.UserDaoImpl.findByUsername(..))" id="pc1"/>
<aop:before method="before" pointcut-ref="pc1"/>
<aop:after-returning method="returnAfter" pointcut-ref="pc1"/>
<aop:after-throwing method="thowingAfter" throwing="t" pointcut-ref="pc1"/>
<aop:after method="fainlly" pointcut-ref="pc1"/>
<aop:around method="around" pointcut-ref="pc1"/>
</aop:aspect>
</aop:config>
</beans>




 基于aspectj注解aop实现






@Aspect
public class AdviceSupport {
     @Pointcut("execution(* com.zhidisort.dao.impl.UserDaoImpl.findByUsername(..))")
public void pc1(){
 
}
     /**
      * 前置通知
      * @param jp
      */
     @Before("pc1()")
public void before(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"前置通知");
}
      /**
       * 返回后通知
       * @param jp
       */
@AfterReturning("pc1()")
public void returnAfter(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"方法正常执行结束");
}
/**
* 异常抛出通知
* @param jp
* @param t
*/
@AfterThrowing(value="pc1()", throwing="t")
public void thowingAfter(JoinPoint jp,Throwable t){
System.out.println(jp.getSignature().getName()+"异常信息通知"+t.getMessage());
}
/**
* 最终通知
* @param jp
*/
@After("pc1()")
public void fainlly(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"方法正常执行结束最终通知");
}
/**
* 环绕通知
* @param jp
* @return
* @throws Throwable
*/
@Around("pc1()")
public  Object around(ProceedingJoinPoint jp) throws Throwable{

long begin=System.currentTimeMillis();

Object object=jp.proceed();
long end=System.currentTimeMillis();

System.out.println(jp.getSignature().getName()+"执行时间"+(end-begin)+"毫秒");
return object;
}
}
/**
 *
 *测试类
 *
 */




public class TestAop {


public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aspectj-aop.xml");
IUserDao userDao = context.getBean(IUserDao.class);

userDao.save(null);

userDao.findByUsername("");
}


}




xml配置信息




<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
                   http://www.springframework.org/schema/beans/spring-beans.xsd
                   http://www.springframework.org/schema/context
                   http://www.springframework.org/schema/context/spring-context.xsd




 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  
<context:component-scan base-package="com.zhidisort.**.impl"/>
<bean class="com.zhidisort.advice.AdviceSupport" id="adviceSupport"/>


</beans>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值