SpringAOP实现代理-6(注解,组件)
- 注解的方式实现切面类,并且5种通知方法都可以使用注解完成
- 环绕通知参数列表需传入 ProceedingJoinPoint , ProceedingJoinPoint执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别.
- aspectj-autoproxy标签实现自动代理
- 需要在代理的beans.xml文件中添加context的声名
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-aop.xsd">
-
注解为了避免相同的匹配规则被定义多处,专门定义一个方法设置执行的匹配规则,需要调用相同规则的,直接调用该方法即可
-
目标类UserServiceImpl.java(已实现接口)
public class UserServiceImpl implements UserService {
@Override
public List getUser() {
System.out.println("getUser");
return null;
}
@Override
public boolean saveUser(Object user) {
System.out.println("saveUser");
return false;
}
@Override
public boolean deleteUser(int userId) {
System.out.println("deleteUser");
return false;
}
@Override
public boolean updataUser(Object user) {
System.out.println("updataUser");
return false;
}
}
- 以注解的方式实现切面类Aspect.java
- 当前类的5种通知方法均以注解的方式完成
- JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
- getSignature();获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
- getArgs();获取传入目标方法的参数对象
- getTarget();获取被代理的对象
- getThis();获取代理对象
- JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
@Component //标注当前类是一个组件
@org.aspectj.lang.annotation.Aspect //标注当前类是一个切面类
public class Aspect {
/**
* Description: 定义一个注解方法,其中匹配规则是(* com.aop.aop6.*.*(..)),当其他通知匹配该规则的时候,直接在注解中引用该方法
*/
@Pointcut(value ="execution(* com.aop.aop6.*.*(..))")
public void proxyAll(){}
/**
* Description: 表示前置通知
*/
@Before("proxyAll()")
public void beforeTest(JoinPoint jp){
//在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
System.out.println("args "+jp.getArgs());
System.out.println("before");
}
/**
* Description: 表示后置通知
*/
@After("proxyAll()")
public void afterTest(){
System.out.println("after");
}
/**
* Description: 环绕通知
* @param: pjp:处理连接点
*/
@Around("proxyAll()")
public Object aroundTest(ProceedingJoinPoint pjp){ //环绕通知要有返回内容
//环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行,
// 这也是环绕通知和前置、后置通知方法的一个最大区别。
Object obj=null;
try {
System.out.println("around before");
obj = pjp.proceed(); //环绕通知需要传入ProceedingJoinPoint并执行proceed方法.
System.out.println("around after");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return obj;
}
/**
* Description: 表示带返回值的通知
* @param: jpj :连接点 ; obj : 业务方法的返回值
*/
@AfterReturning(value = "proxyAll()" , returning = "obj")
public void returnTest(JoinPoint jp,Object obj){
System.out.println("after return");
System.out.println(obj);
System.out.println("jp-toString "+jp.toString());
}
/**
* Description: 带异常的通知
* @param: jpj :连接点 ; e : Throwable对象
*/
public void throwingTest(JoinPoint jp,Throwable e){
System.out.println("after throwing");
System.out.println(e.getMessage());
}
}
- 代理的.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: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 : 指定扫描包的路径
-->
<context:component-scan base-package="com.aop.aop6" />
<!--aop:aspectj-autoproxy : 实现自动代理-->
<aop:aspectj-autoproxy />
</beans>
- 单元测试
public class AOPTest6 {
@Test
public void testAOP(){
ApplicationContext ac=new ClassPathXmlApplicationContext("aop6/beans.xml");
UserService userService =ac.getBean("us", UserService.class);
userService.getUser();
userService.saveUser(new Object());
userService.deleteUser(2);
userService.updataUser(new Object());
}
}
SpringAOP-实现代理-7(BeanPostProcessor)
- BeanPostProcessor接口是Bean后置处理器。接口实现类有postProcessBeforeInitialization和 afterProcessBeforeInitialization两个方法,分别在bean创建前和创建后出发调用. 因此bean创建之前或者之后对对应bean进行一些处理。这两个方法最终的返回值还是bean。可以是本身,也可以是加工过之后的
- 利用beanpostProcessor,捕获部分bean的加载,并对这些bean生成动态代理,并将代理类放到spring容器中,后续调用原本这个bean类的方法时,就会直接进代理类的invoke方法,实现对某些类的某些方法(利用自定义注解)的增强等
- 创建代理类:利用Proxy.newProxyInstance()方法创建真正的代理类。在postProcessAfterInitialization方法中。 返回的代理类接口的实现子类,不是原实现类的子类。这里是对接口进行代理。
- 采用配置文件式,需要在代理的beans.xml文件中添加context的声名
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-aop.xsd">
- 目标类UserServiceImpl.java(已实现接口)
public class UserServiceImpl implements UserService {
@Override
public List getUser() {
System.out.println("getUser");
return null;
}
@Override
public boolean saveUser(Object user) {
System.out.println("saveUser");
return false;
}
@Override
public boolean deleteUser(int userId) {
System.out.println("deleteUser");
return false;
}
@Override
public boolean updataUser(Object user) {
System.out.println("updataUser");
return false;
}
}
- 以注解的方式实现切面类Aspect.java
public class Aspect {
public void before(){
System.out.println(" Aspect before");
}
public void after(){
System.out.println("Aspect after");
}
}
- 实现扩展接口BeanPostProcessor
/**
* Description: 配置了包扫描后,该类会初始化两个对象EventListenerMethodProcessor和DefaultEventListenerFactory,再外加我们自己的组件对象
所以会有三个before打印
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("before");
System.out.println("bean "+o);
return o;
}
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("after");
return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
//使用匿名回调函数InvocationHandler()
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Aspect aspect=new Aspect();
aspect.before();
Object obj = method.invoke(o, args);
aspect.after();
return obj;
}
});
}
}
- 代理的.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"
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">
<!--
context:component-scan :上下文的组件扫描
base-package : 指定扫描包的路径
-->
<context:component-scan base-package="com.aop.aop7" />
<!--
指定BeanPostProcessor的Factory hook(钩子),让每个bean(对应MyBeanPostProcessor中的参数o)对象初始化是自动回调该对象中的回调方法
-->
<bean class="com.aop.aop7.MyBeanPostProcessor" />
</beans>
- 单元测试
public class AOPTest7 {
@Test
public void testAOP(){
ApplicationContext ac=new ClassPathXmlApplicationContext("aop7/beans.xml");
UserService userService =ac.getBean("us", UserService.class);
userService.getUser();
userService.saveUser(new Object());
userService.deleteUser(2);
userService.updataUser(new Object());
}
}
网友评论