Spring笔记07(Spring AOP的通知advice和顾问advisor)

本文内容纲要:

- 1.Spring AOP的通知advice

- 01.接口代码:

- 02.实现类代码:

- 03.增强通知类:

- 04.applicationContext.xml文件:

- 05.测试代码:

- 2.Spring AOP的顾问advisor

- 01.readMe

- 02.接口代码:

- 03.实现类代码:

- 04.增强类代码:

- 05.applicationContext.xml文件:

- 06.测试代码:

1.Spring AOP的通知advice

01.接口代码:

package cn.pb.dao;

public interface UserDao {

//主业务

String add();

//主业务

void del();

}

02.实现类代码:

package cn.pb.dao;

public class UserDaoImpl implements UserDao{

//主业务

public String add() {

//模拟异常

//int a=8/0;

System.out.println("add ok!");

return "新增成功!";

}

//主业务

public void del() {

System.out.println("del ok!");

}

03.增强通知类:

001.前置增强类:

package cn.pb.advices;

/**

* 前置增强类 实现MethodBeforeAdvice接口

* 在目标对象方法执行之前执行

*/

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeAdvice implements MethodBeforeAdvice {

/**

*

* @param method :目标方法

* @param args :目标方法参数

* @param target :目标对象

* @throws Throwable

*/

public void before(Method method, Object[] args, Object target) throws Throwable {

System.out.println("前置增强====================》");

}

}

002.后置增强类:

package cn.pb.advices;

/**

* 后置增强类 实现AfterReturningAdvice接口

* 在目标对象方法执行之后执行

*/

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterAdvice implements AfterReturningAdvice {

/**

*

* @param target:目标对象

* @param method :目标方法

* @param args :目标方法参数

* @param returnValue :目标方法返回值

* @throws Throwable

*/

public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

System.out.println("后置增强==================》");

}

}

003.环绕增强类:

package cn.pb.advices;

/**

* 环绕增强 :

* 在前置通知 之后,

* 后置通知之前执行环绕通知!

*/

import org.aopalliance.intercept.MethodInterceptor;

import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor {

/**

* 在前置通知 之后,后置通知之前执行环绕通知!

* 可以获取方法的返回值,并且改变!

* @param methodInvocation 方法的执行器, getMethod 包含了方法中的所有方法

* @return

*/

public Object invoke(MethodInvocation methodInvocation) throws Throwable {

System.out.println("执行方法之前的 环绕通知");

//执行目标方法

Object result= methodInvocation.proceed();

if (result!=null){

//对方法的返回值进行修改

result="xiaoheihei";

}

System.out.println("执行方法之后的 环绕通知");

return result;

}

}

004.异常增强类:

package cn.pb.advices;

/**

* 异常增强类:在目标方法出现异常的时候执行

* 实现ThrowsAdvice接口

*/

import org.springframework.aop.ThrowsAdvice;

public class ExceptionAdvice implements ThrowsAdvice{

public void throwsAdvice(){

System.out.println("方法在执行过程中出现了异常!");

}

}

04.applicationContext.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"

xsi:schemaLocation="

http://www.springframework.org/schema/beans

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

<!--01.配置目标对象-->

<bean id="userDao" class="cn.pb.dao.UserDaoImpl"/>

<!--02.配置通知-->

<bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>

<bean id="afterAdvice" class="cn.pb.advices.AfterAdvice"/>

<bean id="aroundAdvice" class="cn.pb.advices.AroundAdvice"/>

<!--03.通过配置代理工厂bean,生成代理类,来把通知织入到目标对象

问题:只能管理 通知!

01.只能将切面织入到目标类的所有方法中!

02.只能配置一个 目标对象

-->

<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<!--注册目标对象 如果nam为target 那么ref="userDao" -->

<property name="targetName" value="userDao"/>

<!--注册通知-->

<property name="interceptorNames" value="beforeAdvice,afterAdvice,aroundAdvice"/>

</bean>

<!--配置异常目标对象-->

<bean id="userException" class="cn.pb.exceptionPackage.UserServiceImpl"/>

<!--配置异常通知-->

<bean id="myException" class="cn.pb.advices.ExceptionAdvice"/>

<!--现在是一个service对应一个ProxyFactoryBean 这样不可以!-->

<bean id="exceptionProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<!--注册目标对象 -->

<property name="targetName" value="userException"/>

<!--注册通知-->

<property name="interceptorNames">

<array>

<value>myException</value> <!--异常通知-->

</array>

</property>

<!--代理类的优化 设置之后程序就会自动选择是使用JDK动态代理还是使用cglib动态代理-->

<property name="optimize" value="true"/>

<!-- <property name="proxyTargetClass" value="true"/>

proxyTargetClass:默认是false ,默认执行jdk动态代理!

设置成true,强制执行cglib!

optimize : 代理类的优化

有接口就是用jdk,没有接口使用cglib动态代理-->

</bean>

<!--

我们的动态代理 (在程序运行期间,动态生成的代理类) 分为两种方式:

01.jdk 只能应用于实现接口的情况

02.cglib 应用于实现接口和类的情况

如果我们是接口的情况,使用jdk效率高!

如果我们是类的情况,必须使用cglib!

问题?

程序 spring容器怎么知道我们是用的类还是接口??

public class ProxyConfig implements Serializable

private boolean proxyTargetClass = false;

private boolean optimize = false;

spring底层默认使用cglib! 现在我们的项目中使用的是接口!

用spring默认的性能不高!

proxyTargetClass 和optimize都是用来设置 我们使用的代理模式是jdk还是cglib!

@Override

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

根据我们配置文件中 proxyTargetClass 和 optimize的配置

if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {

Class<?> targetClass = config.getTargetClass();

if (targetClass == null) {

throw new AopConfigException("TargetSource cannot determine target class: " +

"Either an interface or a target is required for proxy creation.");

}

根据目标对象返回对应的动态代理

if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {

return new JdkDynamicAopProxy(config);

}

return new ObjenesisCglibAopProxy(config);

}

else {

return new JdkDynamicAopProxy(config);

}

}

-->

</beans>

05.测试代码:

package cn.pb;

import cn.pb.dao.UserDao;

import cn.pb.exceptionPackage.ServiceException;

import cn.pb.exceptionPackage.UserException;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAdvice {

/**

* 前置 后置 通知测试

*/

@Test

public void testBefore(){

ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

UserDao service= (UserDao) context.getBean("userProxy");

service.add();

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

service.del();

}

/**

* 环绕 通知测试

*/

@Test

public void testAround(){

ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

UserDao service= (UserDao) context.getBean("userProxy");

String result= service.add();

System.out.println(result);

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

service.del();

}

/**

* 异常通知测试

*/

@Test

public void testException(){

ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

ServiceException service= (ServiceException) context.getBean("exceptionProxy");

try {

service.chechUser("admins",25);

} catch (UserException e) {

e.printStackTrace();

}

}

}

2.Spring AOP的顾问advisor

01.readMe

顾问:在通知的基础之上,在细化我们的aop切面!

通知和顾问都是切面的实现方式!

通知是顾问的一个属性!

顾问会通过我们的设置,将不同的通知,在不通过的时间点,把切面

织入到不同的切入点!

PointCutAdvisor接口!

比较常用的两个实现类:

NameMatchMethodPointcutAdvisor :根据切入点(主业务方法)名称织入切面!

RegexpMethodPointcutAdvisor :根据自定义的正则表达式织入切面!

正则表达式中常用的三个运算符

. 任意单个字符

+ 表示字符出现一次或者多次

* 表示字符出现0次或者多次

02.接口代码:

package cn.pb.dao;

public interface UserDao {

//主业务

void add();

//主业务

void del();

}

03.实现类代码:

package cn.pb.dao.impl;

import cn.pb.dao.UserDao;

public class UserDaoImpl implements UserDao{

//主业务

public void add() {

System.out.println("add ok!");

}

//主业务

public void del() {

System.out.println("del ok!");

}

}

04.增强类代码:

package cn.pb.advices;

/**

* 前置增强类 在目标方法执行之前 执行

* 要实现MethodBeforeAdvice接口

*/

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeAdvice implements MethodBeforeAdvice {

/**

* 在目标方法执行之前

* @param method 目标方法

* @param args 目标方法的参数列表

* @param target 目标对象

* @throws Throwable

*/

public void before(Method method, Object[] args, Object target) throws Throwable {

System.out.println("前置增强==============》");

}

}

05.applicationContext.xml文件:

001.NameMatchMethodPointcutAdvisor :根据切入点(主业务方法)名称织入切面!

<?xml version="1.0" encoding="UTF-8"?>

<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">

<!--01.配置目标对象-->

<bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>

<!--02.配置增强 通知-->

<bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>

<!---配置顾问 实现了 在指定的主业务方法中 增强-->

<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

<!--通知就是顾问中的一个属性-->

<property name="advice" ref="beforeAdvice"/>

<!--配置切入点 这里的切入点指的是 方法的简写!-->

<property name="mappedNames" value="add,del"/>

</bean>

<!--03.配置代理对象-->

<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<!--注册目标对象-->

<property name="target" ref="userDao"/>

<!--注册顾问-->

<property name="interceptorNames" value="myAdvisor"/>

</bean>

</beans>

002.RegexpMethodPointcutAdvisor :根据自定义的正则表达式织入切面!

<?xml version="1.0" encoding="UTF-8"?>

<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">

<!--01.配置目标对象-->

<bean id="userDao" class="cn.pb.dao.impl.UserDaoImpl"/>

<!--02.配置增强 通知-->

<bean id="beforeAdvice" class="cn.pb.advices.BeforeAdvice"/>

<!---配置顾问 实现了 在指定的主业务方法中 增强-->

<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

<!--通知就是顾问中的一个属性-->

<property name="advice" ref="beforeAdvice"/>

<!--配置切入点 这里的切入点指的是 方法的全限定方法名

cn.pb.dao.impl.UserServiceImpl.add

cn.pb.dao.impl.UserServiceImpl.del-->

<!-- <property name="pattern" value=".*add.*"/> 匹配单个方法-->

<!-- <property name="pattern" value=".*mpl.*"/>匹配多个方法-->

<!--<property name="patterns" value=".*add.*,.*del.*"/> 匹配多个方法-->

<property name="pattern" value=".*add.*|.*del.*"/>

</bean>

<!--03.配置代理对象-->

<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<!--注册目标对象-->

<property name="target" ref="userDao"/>

<!--注册顾问-->

<property name="interceptorNames" value="myAdvisor"/>

</bean>

</beans>

06.测试代码:

package cn.pb;

import cn.pb.dao.UserDao;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {

/**

* 测试NameMatchMethodPointcutAdvisor

*/

@Test

public void testNameMethod(){

ApplicationContext context=new

ClassPathXmlApplicationContext("applicationContext.xml");

UserDao proxy= (UserDao) context.getBean("userProxy");

proxy.add();

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

proxy.del();

}

/**

* 测试RegexpMethodPointcutAdvisor

*/

@Test

public void testRegexpMethod(){

ApplicationContext context=new

ClassPathXmlApplicationContext("regexp.xml");

UserDao proxy= (UserDao) context.getBean("userProxy");

proxy.add();

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

proxy.del();

}

}

本文内容总结:1.Spring AOP的通知advice,01.接口代码:,02.实现类代码:,03.增强通知类:,04.applicationContext.xml文件:,05.测试代码:,2.Spring AOP的顾问advisor,01.readMe,02.接口代码:,03.实现类代码:,04.增强类代码:,05.applicationContext.xml文件:,06.测试代码:,

原文链接:https://www.cnblogs.com/lyb0103/p/7658781.html

以上是 Spring笔记07(Spring AOP的通知advice和顾问advisor) 的全部内容, 来源链接: utcz.com/z/362906.html

回到顶部