您的位置:首页 > 编程语言 > Java开发

Spring4第四讲学习笔记,AOP面向切面编程

2017-06-07 23:04 786 查看
bean的作用域,scope 默认是singleton单例,整个容器中只有一个对象实例

prototype原型,每次获取bean对象都产生一个新对象
注意:在整合struts2和spring时,需要将action设置为scope="prototype"

1.静态代理的角色分析,
 抽象角色:一般使用接口或者抽象类实现.interface Rent

 真实角色:被代理的角色 Host   需要实现Rent接口

 代理角色:代理真实角色,代理真实角色后一般会作一些附属操作 需要实现Rent接口

 客户:    使用代理角色来进行一些操作  客户找代理

使用静态代理的好处

1.使得真实角色处理的业务更加纯粹,不再去关注一些公共的事情

2.公共的业务由代理来完成,实现业务的分工

3.公共业务发生扩展的时候,会变得更加集中和方便

缺点:代理类多了,工作量就会变大,开发效率就会降低。


2.动态代理
1.动态代理和静态代理的角色是一样的
2.动态代理的代理类是动态生成的
3.分为两类 一类基于接口的动态代理,如jdk动态代理
,一类是基于类的动态代理,如cglib (读法:C G lib)
现在使用javaisit动态生成
4.jdk动态代理---java反射包中的proxy类InvocationHandler接口,它只能代理接口。

一个动态代理一般代理某一类业务。一个动态代理可以代理多个类。


3.面向切面编程aop aspect oriented programing

 2.aop在Spring中的运用
提供声明事务的服务
允许用户自定义切面


传统的编程模式是JSP--Action----Service---Dao 自上而下,纵向编程

 3.aop在不改变原有的代码的情况下,增加新的功能

   aop编程模式:横向的编程  log()方法插入Service中

   aop的好处:a.使得真实角色处理的业务更加纯粹,不再去关注一些公共的事情
     b.公共的业务由代理类来完成---实现业务的分工
     c.公共业务发生扩展时将会变得更加集中和方便


4.名词解释
关注点:增加的某个业务,如日志,安全,缓存,事务等
切面aspect:一个关注点的模块化。就是把关注点封装成一个类。一个横向的切面可能会横切多个业务类
连接点:表示关注点的执行。
通知advice:在某个业务执行的前后公共业务执行。通知类型分为,前置通知,后置通知,异常通知,最终通知等。
织入weaving:把切面连接到其他对象上。

5.Spring就是封装动态代理,提高开发效率

Spring将公共的业务方法,和业务类关联起来, 执行业务类的时候, Spring也去执行公共的业务方法

spring aop就是将公共的业务如日志安全等和领域业务结合,当执行领域业务时将会把公共的业务加进来,实现公共业务的重复利用。

它使得领域业务更纯粹,程序员专注于领域业务。其本质还是动态代理。


 

具体代码实现:

静态代理代码:就是写一个代理类,里面有一个真实角色的引用,通过代理类的构造器接受这个真实角色,代理类执行真实角色的方法,并附加一些代理类的附属方法。

动态代理代码:

package cn.sxt.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//import cn.sxt.service.UserService;

public class ProxyInovationHandler implements InvocationHandler{
private Object target;// 目标对象--真实对象

public ProxyInovationHandler(Object target) {
//通过构造方法接受真实对象
super();
this.target = target;
}

/**
 * 生成代理类
 * */
public Object getProxy() {
Object wrap = Proxy.newProxyInstacne(this.getClass().getClassLoader(),this.target.getClass().getInterfaces(),this);
return wrap ;
//共有三个参数,第一个是类加载器,
第二个是this.getClass().getClassLoader()或者new Class[]{this.target.getClass()};
注意:由于proxy动态代理是基于接口的动态代理,所以要求目标对象必须是一个接口
第三个是调用处理器接口对象。


}

public void log(String methodName) {
// 用于记录日志
System.out.println("执行" + methodName + "方法");
}
/**
 * proxy是代理类 method 代理类准备执行的方法
 * */
@Override
public Objectinvoke(Object proxy, Method method, Object[] args)
throws Throwable {
log(method.getName());//公共事务,用于记录日志。
return method.invoke(this.target, args);

}

}

3.使用Spring实现aop,面向切面的编程。

导入相关jar包,多了两个古来的jar包。

aopalliance.jar

aspectjweaver.jar

commons-logging-1.1.1.jar

spring-aop-4.1.6.RELEASE.jar

spring-aspects-4.1.6.RELEASE.jar

spring-beans-4.1.6.RELEASE.jar

spring-context-4.1.6.RELEASE.jar

spring-context-support-4.1.6.RELEASE.jar

spring-core-4.1.6.RELEASE.jar

spring-expression-4.1.6.RELEASE.jar

spring-jdbc-4.1.6.RELEASE.jar

spring-orm-4.1.6.RELEASE.jar

spring-tx-4.1.6.RELEASE.jar

spring-web-4.1.6.RELEASE.jar

spring-webmvc-4.1.6.RELEASE.jar

配置文件beans.xml

以前的头文件

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd">
在以前的头文件下增加

beans.xml
<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.xsd  
        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd         ">    

 <bean id="log" class="log.Log"/> 
       <bean id="service" class="service.imp.serviceImp"/>
       <bean id="afterLog" class="log.AfterLog"/>
       <aop:config>
       <!--切入点准备切入的具体业务的具体位置     expression表达式 execution()固定 *所有返回值  -->

       <aop:pointcutexpression="execution(*
service.imp.serviceImp.delete(..))" id="pointcut"/>


//第一个* 表示全部返回值 ..表示任意参数 

       
         <!-- 把切入点和公共业务连接起来,配置通知
-->
         <aop:advisoradvice-ref="log"
pointcut-ref="pointcut"/> 
         <aop:advisor
advice-ref="afterLog" pointcut-ref="pointcut"/>

       </aop:config>
</beans>
公共业务方法 在 业务类的 执行前和执行后 执行。

package log;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

//业务执行前的公共事情,advice:通知
public class Log implements MethodBeforeAdvice{

参数:method被调用的方法,参数列表,哪个对象执行method方法
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
String methodName=method.getName();
String className= target.getClass().getName();
System.out.println("类名为:"+className+"的"+methodName+"方法被执行");
}

}

package log;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class AfterLog implements AfterReturningAdvice{
/**
 * 目标方法执行后执行的通知
 * returnValue--返回值
 * method 被调用的方法对象
 * args 被调用的方法对象的参数
 * target 被调用的方法对象的目标对象

 * */
@Override
public void afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable {
String className = target.getClass().getName();
String methodName= method.getName();
System.out.println("类名是:"+className+"的"+methodName+"方法执行");
System.out.println("返回结果是"+returnValue);

}

}
业务类
package service.imp;

import servicee.service;

public class serviceImp implements service {

@Override
public void add() {
System.out.println("用户增加");
}

@Override
public void delete() {
System.out.println("用户删除");

}

@Override
public void update() {
System.out.println("用户更新");

}

@Override
public void search() {
System.out.println("用户查询");

}

}

测试代码
package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import servicee.service;

public class test {
public static void main(String[] args) {
BeanFactory bf = new ClassPathXmlApplicationContext("beans.xml");
service svc = (service)bf.getBean("service");
svc.delete();//此业务方法一执行,公共事务在此方法前 和 后 都有执行
}

}
第二种方法,使用注解实现AOP编程

公共业务方法单独封装成类,这个类打上@Apspect切面标记

在公共业务方法前面添加@Before 或者@After等 表示在 核心业务执行前或执行后 执行

package log;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

@Aspect

public class Logg {
@Before("execution(*
service.imp.serviceImp.*(..))")  注意还有个表示所有返回值的 * 号

public void before(){
System.out.println("方法执行前执行");
}
@After("execution(* service.imp.serviceImp.*(..))")
public void after(){
System.out.println("方法执行后执行");
}

}
配置文件

<?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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        "> 

       <bean id="log" class="log.Log"/> 

       <bean id="service" class="service.imp.serviceImp"/>

       <bean id="afterLog" class="log.AfterLog"/>

       <bean id="newLog" class="log.Logg"/>

      <!--  <aop:config>

        切入点准备切入的具体业务的具体位置     expression表达式 execution()固定 *所有返回值 

        <aop:pointcut expression="execution(* service.imp.serviceImp.delete(..))" 

        id="pointcut"/>

         
把切入点和公共业务连接起来,配置通知

         
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/> 

         
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>

       </aop:config> -->

       <aop:aspectj-autoproxy/> 注意书写 切面j-自动代理

   

 </beans>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: