Spring框架初识(二)

1. AOP的相关概念

 

    1.1 AOP概述

        1.1.1 什么是AOP

            AOP:全程是Aspect Oriented Programming 即面向切面编程。是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

  1.1.2 AOP的作用及优势

            作用:在程序运行期间,不需要修改源码,对已有的程序方法进行增强

            优势:减少重复代码,提高开发效率,维护方便

1.1.3 AOP的实现方式

  使用动态代理技术(CGLIB,Proxy)

    1.2 AOP的具体应用

         1.2.1 动态代理回顾  

            因AOP主要通过动态代理实现,在学习AOP之前,先来回顾动态代理的相关知识。

1.2.1.1 动态代理的特点

      • 字节码随用随创建,随用随加载。
      • 它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。
      • 装饰者模式就是静态代理的一种体现。

1.2.1.2 动态代理的实现方式                


代理方式

提供者

要求

基于接口的动态代理

JDK官方的Proxy类

被代理类最少实现一个接口

基于子类的动态代理

第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar

被代理类不能用final修饰的类(最终类)
  • 基于接口的动态代理案例

/**原方法**/

package com.zycom.serviceimpl;

import com.zycom.service.ICustomerService;

public class CustomerServiceImpl implements ICustomerService{

@Override

public void save() {

System.out.println("服务层:保存...");

}

}

 

/**增强方法**/

package com.zycom.utils;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import com.zycom.service.ICustomerService;

public class MyProxy {

public static ICustomerService getProxyCustomerService(final ICustomerService c){

ICustomerService cs = (ICustomerService)Proxy.newProxyInstance(MyProxy.class.getClassLoader(),c.getClass().getInterfaces(), new InvocationHandler() {

@Override

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

if("save".equals(method.getName())){

System.out.println("Proxy对save方法进行增强...");

}

return method.invoke(c, args);

}

});

return cs;

}

}

/**测试方法*/

public void t1(){

CustomerServiceImpl c = new CustomerServiceImpl();

System.out.println("增强前:");

c.save();

System.out.println("---------------------------------------");

System.out.println("增强后:");

ICustomerService cs = MyProxy.getProxyCustomerService(c);

cs.save();

}

  • 基于子类的动态代理案例

        该方法需要导入第三方jar包:CGlib包已包含在Spring的核心包内,如果导入Spring不需要在单独导入CGLib的jar包

/**源代码**/

package com.zycom.domain;

public class User {

public void eat(){

System.out.println("用户在吃饭...");

}

}

/**增强代码**/

/**

* 通过CGLib的方式增强类的方法

*/

public static User getProxyUser(final User u) {

User user = (User) Enhancer.create(u.getClass(), new MethodInterceptor() {

@Override

public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy)

throws Throwable {

if("eat".equals(method.getName())){

System.out.println("我来记录user吃了什么(增强)");

}

return methodProxy.invoke(u, args);

}

});

return user;

}

/**测试代码**/

public void t2(){

User u = new User();

System.out.println("增强前:");

u.eat();

System.out.println("--------------------------------------");

System.out.println("增强后");

User user = MyProxy.getProxyUser(u);

user.eat();

}

 

1.3 Spring中的AOC

1.3.1 动态代理的选择

在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

   

     1.3.2AOP相关术语

    

Joinpoint(连接点--类中所有的方法):

所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。

Pointcut(切入点--需要被增强的方法):

所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。

Advice(通知/增强--增强的功能):

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。

通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Introduction(引介):

引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。

Target(目标对象--被增强的对象):

代理的目标对象。

Weaving(织入):

是指把增强应用到目标对象来创建新的代理对象的过程。

spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

Proxy(代理):

一个类被AOP织入增强后,就产生一个结果代理类。

Aspect(切面):

是切入点和通知(引介)的结合。

    

    1.3.3 学习spring中的AOP要明确的事

a、开发阶段(我们做的)

编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。

把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP编程人员来做。

在配置文件中,声明切入点与通知间的关系,即切面。:AOP编程人员来做。

b、运行阶段(Spring框架完成的)

Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

2.基于XML的AOP配置

    2.1 环境搭建

 

2.1.1 导包

AOP相关包

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

spring-aspects-4.2.4.RELEASE.jar

spring-aop-4.2.4.RELEASE.jar

日志包

com.springsource.org.apache.commons.logging-1.1.1.jar

com.springsource.org.apache.log4j-1.2.15.jar

Spring基本包 

spring-beans-4.2.4.RELEASE.jar

spring-context-4.2.4.RELEASE.jar

spring-core-4.2.4.RELEASE.jar

spring-expression-4.2.4.RELEASE.jar

spring-test-4.2.4.RELEASE.jar


        2.1.2 创建接口和实现类

/**接口**/

package com.zycom.service;

public interface ICustomerService {

public abstract void save();

}

/**实现类**/

package com.zycom.serviceimpl;

import com.zycom.service.ICustomerService;

public class CustomerServiceImpl implements ICustomerService{

@Override

public void save() {

System.out.println("服务层:保存...");

}

}

2.1.3 创建切面类和通知(增强方法所在的类和要增强的功能方法)

package com.zycom.proxy;

public class MyProxy {

public void log(){

System.out.println("记录日志...");

}

}

    2.1.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: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">

</beans>

       2.1.5 将实现类交由IOC管理

<bean id="customerService" class="com.zycom.serviceimpl.CustomerServiceImpl"></bean>

2.2配置步骤

2.2.1 将切面类交由IOC管理

<bean id="myProxy" class="com.zycom.proxy.MyProxy"></bean>

            2.2.2 配置AOP

        方式一:

<aop:config>

<aop:aspect id="proxy" ref="myProxy">

<aop:before method="log" pointcut="execution(public void com.zycom.serviceimpl.CustomerServiceImpl.save())"/>

</aop:aspect>

</aop:config>

        方式二:

<aop:config>

<aop:pointcut expression="execution(* com.zycom.serviceimpl.CustomerServiceImpl.save(..))" id="save"/>

<aop:aspect id="proxy" ref="myProxy">

<aop:after-returning method="log" pointcut-ref="save"/>

</aop:aspect>

</aop:config>


    2.3 切入点表达式说明

execution:

匹配方法的执行(常用)

execution(表达式)

表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))

写法说明:

 全匹配方式:

public void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()

 访问修饰符可以省略    

void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()

  返回值可以使用*号,表示任意返回值

* com.itheima.service.impl.CustomerServiceImpl.saveCustomer()

 包名可以使用*号,表示任意包,但是有几级包,需要写几个*

* *.*.*.*.CustomerServiceImpl.saveCustomer()

使用..来表示当前包,及其子包

* com..CustomerServiceImpl.saveCustomer()

 类名可以使用*号,表示任意类

* com..*.saveCustomer()

方法名可以使用*号,表示任意方法

* com..*.*()

 参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数

* com..*.*(*)

参数列表可以使用..表示有无参数均可,有参数可以是任意类型

* com..*.*(..)

全通配方式:

* *..*.*(..)

  2.4 常用标签


标签

作用

属性

说明

<aop:config>

用于声明开始aop的配置

 

 

<aop:aspect>

用于配置切面。

id:给切面提供一个唯一标识。

ref:引用配置好的通知类bean的id。


 

<aop:pointcut>

用于配置切入点表达式

expression:用于定义切入点表达式。

id:用于给切入点表达式提供一个唯一标识。


 

<aop:before>

用于配置前置通知

method:指定通知中方法的名称。

pointct:定义切入点表达式

pointcut-ref:指定切入点表达式的引用


用于配置前置通知。前置通知的执行时间点:切入点方法执行之前执行

<aop:after-returning>

用于配置后置通知

method:指定通知中方法的名称。

pointct:定义切入点表达式

pointcut-ref:指定切入点表达式的引用


用于配置后置通知。后置通知的执行时间点:切入点方法正常执行之后。它和异常通知只能有一个执行

<aop:after-throwing>

用于配置异常通知

method:指定通知中方法的名称。

pointct:定义切入点表达式

pointcut-ref:指定切入点表达式的引用


用于配置异常通知。异常通知的执行时间点:切入点方法执行产生异常后执行。它和后置通知只能执行一个。

<aop:after>

用于配置最终通知

method:指定通知中方法的名称。

pointct:定义切入点表达式

pointcut-ref:指定切入点表达式的引用


用于配置最终通知。最终通知的执行时间点:无论切入点方法执行时是否有异常,它都会在其后面执行。

<aop:around>

用于配置环绕通知

method:指定通知中方法的名称。

pointct:定义切入点表达式

pointcut-ref:指定切入点表达式的引用


用于配置环绕通知。他和前面四个不一样,他不是用于指定通知方法何时执行的。

2.5 通知类型

2.5.1 普通类型配置(<aop:before>|<aop:after-returning>|<aop:after-throwing>|<aop:after>)

<aop:before method="beforePrintLog" pointcut-ref="pt1"/>

<aop:after-returning method="afterReturningPrintLog"  pointcut-ref="pt1"/>

<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"/>

<aop:after method="afterPrintLog" pointcut-ref="pt1"/>

<aop:around method="aroundPringLog" pointcut-ref="pt1"/>

2.5.2 <aop:around>标签的配置

首先需要对切面类的增强方法有特殊要求:

public void aroundMethod(ProceedingJoinPoint pp){

try {

System.out.println("方法执行前增强功能...");

pp.proceed();

System.out.println("方法执行后增强功能...");

} catch (Throwable e) {

e.printStackTrace();

}

}

配置文件:

<aop:config>

<aop:pointcut expression="execution(* com.zycom.serviceimpl.CustomerServiceImpl.find(..))" id="find"/>

<aop:aspect id="proxy" ref="myProxy">

<aop:around method="aroundMethod" pointcut-ref="find"/>

</aop:aspect>

</aop:config>

3.基于注解的AOP配置

     3.1环境搭建

        3.1.1 编写业务层接口和业务层实现类(并通过注解将实现类交由Sping的ioc来管理)

业务层接口

package com.zycom.service;

public interface IUserService {

public abstract void login();

public abstract void quit();

}

业务层实现类

package com.zycom.serviceimpl;

import org.springframework.stereotype.Service;

import com.zycom.service.IUserService;

@Service("userService")

public class UserServiceImpl implements IUserService {

@Override

public void login() {

System.out.println("服务层:登录");

}

@Override

public void quit() {

System.out.println("服务层:退出");

}

}

3.1.2 导包

与上方xml配置的包相同

     3.1.3 xml配置文件导入约束

与上方xml配置的约束相同

3.1.4 配置xml开启扫描

<!-- 1.开启包扫描 -->

<context:component-scan base-package="com.zycom"></context:component-scan>

3.2 配置步骤

    3.2.1 将通知类通过注解交给spring管理,在方法上通过注解表明通知方式和切入点

package com.zycom.proxy;

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.springframework.stereotype.Component;

//将通知类交由IOC管理

@Component("myProxy")

// 声明切面类

@Aspect

public class MyProxy {

@AfterReturning("execution(* com.zycom.serviceimpl.UserServiceImpl.login())")

public void enhanceLogin() {

System.out.println("xxxx先生,欢迎您的登录...");

}

@Around("execution(* com.zycom.serviceimpl.UserServiceImpl.quit() )")

public void enhanceQuit(ProceedingJoinPoint pp) {

try {

System.out.println("您确定要退出吗?");

pp.proceed();

System.out.println("已退出,欢迎再来...");

} catch (Throwable e) {

System.out.println("退出失败,请重试");

e.printStackTrace();

}

}

}

        3.2.2 在spring配置文件中开启spring对注解AOP的支持

<!-- 2.开启注解模式 -->

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3.3 常用通知注解


注解

作用

属性

与xml配置文件对应标签

@Aspect

把当前类声明为切面类

 

<aop:aspect>

@Before

把当前方法看成是前置通知

value:用于指定切入点表达式,还可以指定切入点表达式的引用

<aop:before>

@AfterReturning

把当前方法看成是后置通知

value:用于指定切入点表达式,还可以指定切入点表达式的引用

<aop:after-returning>

@AfterThrowing

把当前方法看成是异常通知

value:用于指定切入点表达式,还可以指定切入点表达式的引用

<aop:after-throwing>

@After

把当前方法看成是最终通知

value:用于指定切入点表达式,还可以指定切入点表达式的引用

<aop:after>

@Around

把当前方法看成是环绕通知

value:用于指定切入点表达式,还可以指定切入点表达式的引用

<aop:around>

@Pointcut

指定切入点表达式

value:指定表达式的内容

<aop:pointcut>

  3.4 不使用XML的配置方式

package com.zycom.springconfig;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration

@ComponentScan(basePackages={"com.zycom"})

@EnableAspectJAutoProxy

public class SpringCfg {

}

测试类加载:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes={SpringCfg.class})

public class Demo {

@Resource(name="userService")

private IUserService us;

@Test

public void t1(){

us.login();

}

@Test

public void t2(){

us.quit();

}

}

body,td { font-family: 微软雅黑; font-size: 10pt }

时间: 2024-08-11 03:26:45

Spring框架初识(二)的相关文章

Spring框架初识(一)

1. Spring框架概述 1.1 简介 Spring是分层的Java SE/EE应用 full-stack轻量级开源框架,以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架.   1.2 优点 方便解耦,简

Spring框架(二)

Spring反射机制: 1, 通过spring来获取一个对象的实例 1 <bean id="user" class="com.model.User"> 2 3 </bean> 1 ApplicationContext ac=new ClassPathXmlApplicationContext("Spring-all.xml");//调用此方法时类已经实例化好了 2 User u=(User)ac.getBean("

使用Spring框架入门二:基于注解+XML配置的IOC/DI的使用

一.简述 本文主要讲使用注解+xml配合使用的几种使用方式.基础课程请看前一节. 二.步骤 1.为Pom.xml中引入依赖:本例中使用的是spring-context包,引入此包时系统会自动导入它的依赖包spring-beans\spring-core\spring-expression\spring-context. <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http:

Spring框架总结(二)

开发一个简单的Spring项目: 一.开发环境搭建: 1.引入源码jar :3.0以前的版本含有依赖jar包,3.0以后只有spring的核心jar 包 core的jar包 commons-logging-1.1.3.jar spring-beans-3.2.5.RELEASE.jar spring-context-3.2.5.RELEASE.jar spring-core-3.2.5.RELEASE.jar spring-expression-3.2.5.RELEASE.jar jar包可以在

Spring框架(二) ---- bean的歧义性

自动装配bean时,如果符合条件的bean超过一个,就会出现歧义性,抛出NoUniqueBeanDefinitionException异常,有如下两种方法保证bean的唯一性: 一.使用@Primary注解标记首选bean 1.与@Component注解组合使用在自动扫描的bean上 2.与@Bean注解组合使用在java配置中 3.使用primary="true"属性在xml配置中的bean标签上 二.使用@Qualifier注解限定选择bean 1.与@Autowired注解组合使

Spring框架学习总结(上)

目录 1.Spring的概述 2.Spring的入门(IOC) 3.Spring的工厂类 4.Spring的配置 5.Spring的属性注入 6.Spring的分模块开发的配置 @ 1.Spring的概述 在学习SSM框架中,我建议初学者最好先学Spring框架,其次mybatis接着springMVC,先学mybatis当然也是可以的,今天我们就以绝对优雅的姿态闯进Spring世界,系好安全带,准备好了吗,出发了哦!!!咳咳....平时开发接触最多的估计就是IOC容器,它可以装载bean(所谓

spring框架学习(二)依赖注入

转自:http://blog.csdn.net/lishuangzhe7047/article/details/20740835 ———————————————————————————————————————————— spring框架为我们提供了三种注入方式,分别是set注入,构造方法注入,接口注入.接口注入不作要求,下面介绍前两种方式. 1,set注入 采用属性的set方法进行初始化,就成为set注入. 1)给普通字符类型赋值. [java] view plaincopyprint? pub

[Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.

前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习. 一, AspectJ的概述: AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件. Spring为了简化自身的AOP的开发,将AspectJ拿过来作为Spring自身一个AOP的开发.

跟着刚哥学习Spring框架--Spring容器(二)

Spring容器 启动Spring容器(实例化容器) -- IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化(加载启动),这样才可以从容器中获取Bean的实例并使用.  Bean是Spring管理的基本单位,任何的Java对象和组件都被当成Bean处理,容器还负责管理Bean与Bean之间的依赖关系.  两种类型的启动实现   1.BeanFactory:IOC容器的基本实现,是Spring框架的基础设施,面向Spring本身: -- Spring容器最基本的接口就是BeanF