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

Spring4框架----aop编程思想(03)

2017-10-30 08:57 190 查看

一、Spring的AOP编程

  1、概念:AOP表示的是面向切面编程

        好处:在不修改源代码的情况下,可以实现功能的增强

  2、AOP的实现原理

        jdk的动态代理(掌握)

注意:jdk动态代理只能对实现了接口的类产生代理

/**
 * Jdk的动态代理
 * @author kevin
 */
public class JdkProxy
implements InvocationHandler{
 
//要代理的对象
private CustomerDao
customerDao;
public JdkProxy(CustomerDao
customerDao){
this.customerDao =
customerDao;
}
/**
 * 生成代理对象的方法
 * @return
 */
public CustomerDao createProxy(){
CustomerDao
proxy = (CustomerDao) Proxy.newProxyInstance(customerDao.getClass().getClassLoader(),
customerDao.getClass().getInterfaces(),
this);
return proxy;
}
 
/**
 * 增强的方法
 */
@Override
public Object invoke(Object
proxy, Method
method, Object[]
args)
throws Throwable {
System.out.println("权限校验...");
return method.invoke(customerDao,
args);
}
}
编写代码测试:

@Test
public void test1(){
CustomerDao
customerDao =
new CustomerDaoImpl();
JdkProxy
jdkProxy =
new JdkProxy(customerDao);
CustomerDao
proxy = jdkProxy.createProxy();
proxy.save();

3、 Cglib动态代理(欣赏)

注意:Cglib可以对没有实现接口的类产生代理,生成子类来实现功能的增强

public class CglibProxy
implements MethodInterceptor{
 
//要代理的对象
private LinkManDao
linkManDao;
public CglibProxy(LinkManDao
linkManDao) {
this.linkManDao =
linkManDao;
}
public LinkManDao createProxy(){
//创建Cglib核心类
Enhancer
enhancer =
new Enhancer();
//设置父类
enhancer.setSuperclass(linkManDao.getClass());
//设置回调
enhancer.setCallback(this);
//生成代理
LinkManDao
proxy = (LinkManDao)
enhancer.create();
return proxy;
}
 
@Override
public Object intercept(Object
proxy, Method
method, Object[]
args, MethodProxy
methodProxy)
throws Throwable {
System.out.println("日志记录");
Object
obj = methodProxy.invokeSuper(proxy,
args);
return obj;
}
}
 编写测试代码

@Test
public void test2(){
LinkManDao
linkManDao =
new LinkManDao();
CglibProxy
cglibProxy =
new CglibProxy(linkManDao);
LinkManDao
proxy = cglibProxy.createProxy();
proxy.save();
}

二、Spring 的AOP开发方式(xml)方式

1、Spring的AOP相关术语的介绍

public class UserDaoImpl{

         public void save(){}

         public void delete(){}

         public void list(){}

         public void update(){}

}

Target:目标我们需要UserDaoImpl来增强,该类就可以称作为Target

JoinPoint:连接点,在实际开发中可以被增强的点

PointCut:切入点在实际开发中真正被增强的点就称作为PointCut

Advice:通知,我们需要在save()方法中加一个日志记录功能,我们就需要写一个入职记录的方法,那么该方法就是一个通知(增强)

WeAVing:织入,把通知加入到连接点的过程叫做织入

Proxy:代理,增强之后的对象就叫做代理

Introduction:引介,指的是类层面的增强,不需要进行掌握

Aspect:切面,多个advice和PointCut的组合

2、导入AOP开发所需要的jar包

(1) AOP联盟的jar包:com.springsource.org.aopalliance-1.0.0.jar

(2)Spring提供的AOP的jar包:spring-aop-4.2.4.RELEASE.jar

(3)AspectJ的jar包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

(4)Spring整合AspectJ的jar包:spring-aspects-4.2.4.RELEASE.jar

实例演示;

2.1 编写接口和实现类

 

ProductDao接口:

public interface ProductDao {
 
/**
 * 持久层:产品保存
 */
public void save();
}
ProductDaoImpl实现类:

public class ProductDaoImpl
implements ProductDao {
 
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
 

}

2.2 配置相关类Spring容器中(也就是把相关类交给Spring容器进行管理,来实现)

<?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"
    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">
  
  <bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
   
</beans>

2.3 编写切面类

/**
 * 自定义切面类
 * @author kevin
 */
public class MyAspectXml {
 
public void checkPrivilege(){
System.out.println("权限校验...");
}
}

2.4 配置切面类

<?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"
    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">
  
  <bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
  <bean id="myAspectXml" class="cn.itcast.aspect.MyAspectXml"></bean>
</beans>

2.5 进行AOP配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/X
18dec
MLSchema-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">
  
  <bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
  <bean id="myAspectXml" class="cn.itcast.aspect.MyAspectXml"></bean>
  <!-- AOP配置 -->
  <aop:config>
  <!-- 配置切入点 -->
  <aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
  <!-- 配置切面 -->
  <aop:aspect ref="myAspectXml">
  <aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
  </aop:aspect>
  </aop:config>
</beans>

2.6 编写测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOP {
@Autowired
private ProductDao productDao;
 
@Test
public void test1(){
productDao.save();
}
}
这个时候发现切面类已经被增强了,也就是在原来的基础上对切面进行增强实现

2.7 切入点表达式的语法

语法:

[修饰符]
返回类型 包名.类名.方法名(形式参数)

 execution(public * *(..)) 所有的public方法

 execution(* set(..)) 所有set开头的方法

 execution(* com.xyz.service.AccountService.*(..))    AccountService类中的所有方法

 execution(* com.xyz.service.*.*(..))
com.xyz.service包下所有的方法


 execution(* com.xyz.service..*.*(..))    com.xyz.service包及其子包下所有的方法

2.8 Spring中的AOP通知类型

  2.8.1 前置通知:在方法执行之前增强,可以获得切入点信息

    

<!-- AOP配置 -->
<aop:config>
  <!-- 配置切入点 -->
  <aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
  <!-- 配置切面 -->
  <aop:aspect ref="myAspectXml">
  <!-- 前置通知 -->
  <aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
  </aop:aspect>
</aop:config>
测试:

public class MyAspectXml {
 
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
 
}

    2.8.2 后置通知 在方法执行完之后增强。可以获取返回值信息。

<!-- AOP配置 -->
  <aop:config>
  <!-- 配置切入点 -->
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
  <!-- 配置切面 -->
  <aop:aspect ref="myAspectXml">
  <!-- 前置通知 -->
  <aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
  <!-- 后置通知 -->
  <aop:after-returning method="afterReturn" pointcut-ref="pointcut2"
returning="result"/>
  </aop:aspect>
  </aop:config>
测试:

/**
 * 自定义切面类
 * @author kevin
 */
public class MyAspectXml {
 
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
}
 

public class ProductDaoImpl
implements ProductDao {
 
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
 
}

2.8.3  环绕通知:在方法执行前后都进行增强。可以阻止方法的执行。

<!-- AOP配置 -->
<aop:config>
  <!-- 配置切入点 -->
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
  <!-- 配置切面 -->
  <aop:aspect ref="myAspectXml">
  <!-- 前置通知 -->
  <aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
  <!-- 后置通知 -->
  <aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
  <!-- 环绕通知 -->
  <aop:around method="around" pointcut-ref="pointcut3"/>
  </aop:aspect>
</aop:config>
测试:
public class ProductDaoImpl
implements ProductDao {
 
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
 
@Override
public void update() {
System.out.println("持久层:产品更新");
}
 
}
 

public class MyAspectXml {
 
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
public Object around(ProceedingJoinPoint
joinpoint){
System.out.println("环绕前执行");
Object
obj = null;
try {
 obj = joinpoint.proceed();
} catch (Throwable
e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
}

2.8.4 异常抛出通知:当发生异常之后增强,可以获取异常信息。

<!-- AOP配置 -->
 <aop:config>
  <!-- 配置切入点 -->
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
  <aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
  <!-- 配置切面 -->
  <aop:aspect ref="myAspectXml">
  <!-- 前置通知 -->
  <aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
  <!-- 后置通知 -->
  <aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
  <!-- 环绕通知 -->
  <aop:around method="around" pointcut-ref="pointcut3"/>
  <!-- 抛出异常通知 -->
  <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
  </aop:aspect>
</aop:config>
测试:

public class ProductDaoImpl
implements ProductDao {
 
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
 
@Override
public void update() {
System.out.println("持久层:产品更新");
}
 
@Override
public void find() {
System.out.println("持久层:查询");
int i = 10/0;
}
 
}
 

public class MyAspectXml {
 
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
public Object around(ProceedingJoinPoint
joinpoint){
System.out.println("环绕前执行");
Object
obj = null;
try {
 obj =
joinpoint.proceed();
} catch (Throwable
e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知:" +
ex.getMessage());
}
}


2.8.5 最终通知:不管是否有异常,都会执行

配置:

<!-- AOP配置 -->
  <aop:config>
  <!-- 配置切入点 -->
  <aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
  <aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
  <aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
  <aop:pointcut expression="execution(*
cn.itcast.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
  <!-- 配置切面 -->
  <aop:aspect ref="myAspectXml">
  <!-- 前置通知 -->
  <aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
  <!-- 后置通知 -->
  <aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
  <!-- 环绕通知 -->
  <aop:around method="around" pointcut-ref="pointcut3"/>
  <!-- 抛出异常通知 -->
  <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
  <!-- 最终通知 -->
  <aop:after method="after"
pointcut-ref="pointcut4"/>
  </aop:aspect>
  </aop:config>
测试代码:
public class MyAspectXml {
 
public void checkPrivilege(JoinPoint
point){
System.out.println("权限校验..." +
point);
}
public void afterReturn(Object
result){
System.out.println("后置通知:" +
result);
}
public Object around(ProceedingJoinPoint
joinpoint){
System.out.println("环绕前执行");
Object
obj = null;
try {
 obj =
joinpoint.proceed();
} catch (Throwable
e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知:" +
ex.getMessage());
}
public void after(){
System.out.println("最终通知");
}
}

最终通知和后置通知的区别:最终通知,不管异常与否,都执行。而后置通知在异常的时候不执行

三、Spring注解形式的AOP入门

        第一步、创建工程引入jar包,创建核心配置文件

   3.1  配置文件   

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
       <context:component-scan base-package="cn.itcast"></context:component-scan>
        <!-- 开启自动代理注解 -->
       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

       3.2 创建接口和实现类

public interface ProductDao {
 
/**
 * 持久层:产品保存
 */
public void save();
public int delete();
public void update();
public void find();
}
 

@Repository("productDao")
public class ProductDaoImpl
implements ProductDao {
 
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
 
@Override
public void update() {
System.out.println("持久层:产品更新");
}
 
@Override
public void find() {
System.out.println("持久层:查询");
}
 
}

3.3  面向切面编程 编写切面类

@Component("myAspectAnnotation")
@Aspect
public class MyAspect {
 //前置方法
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}
 
}
提示:此处的切面类可以不取id.

四、Spring的AOP注解通知

4.1 前置通知、

/**

 * 前置通知
 * @param joinPoint
 */
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}


4.2. 后置通知

@Aspect
public class MyAspect {
 
/**
 * 前置通知
 * @param joinPoint
 */
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}
 
@AfterReturning(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))",returning="result")
public void afterReturning(Object
result){
System.out.println("后置通知:" +
result);
}
}


}

4.3. 环绕通知

@Around("execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))")
public Object after(ProceedingJoinPoint
joinpoint)
throws Throwable{
System.out.println("环绕通知前增强");
Object
obj = joinpoint.proceed();
System.out.println("环绕通知后增强");
return obj;
}


4.4. 异常通知

@AfterThrowing(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))",throwing="ex")
public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知");
}


4.5. 最终通知

@After("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
public void after(){
System.out.println("最终通知");
}


4.6. PointCut注解(了解)

作用:用于定义切入点表达式的一个注解。

@Component("myAspectAnnotation")
@Aspect
public class MyAspect {
 
/**
 * 前置通知
 * @param joinPoint
 */
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint
joinPoint){
System.out.println("权限校验..." +
joinPoint.toString());
}

@AfterReturning(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))",returning="result")
public void afterReturning(Object
result){
System.out.println("后置通知:" +
result);
}

@Around("execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))")
public Object aroung(ProceedingJoinPoint
joinpoint)
throws Throwable{
System.out.println("环绕通知前增强");
Object
obj = joinpoint.proceed();
System.out.println("环绕通知后增强");
return obj;
}

//@AfterThrowing(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))",throwing="ex")
@AfterThrowing(value="MyAspect.pointcut()",throwing="ex")
public void afterThrowing(Exception
ex){
System.out.println("抛出异常通知");
}

//@After("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
@After("MyAspect.pointcut()")
public void after(){
System.out.println("最终通知");
}

@Pointcut("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
public void pointcut(){

}

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