spring代理之AOP代理
aop代理是spring的重重之重,也有的时候称之为面向切面编程。
aop代理可以用注解配置和xml配置
我们先用注解配置
IUserDao.java
package cn.itcast.e_aop_anno;
// 接口
public interface IUserDao {
void save();
}
UserDao.java
package cn.itcast.e_aop_anno;
import org.springframework.stereotype.Component;
/**
* 目标对象
* @author Jie.Yuan
*
*/
@Component // 加入容器
public class UserDao implements IUserDao{
@Override
public void save() {
System.out.println("-----核心业务:保存!!!------");
}
}
OrderDao.java
package cn.itcast.e_aop_anno;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* 目标对象
* @author Jie.Yuan
*
*/
@Component("orderDao") // 加入容器
@Scope("prototype")
public class OrderDao{
public void save() {
System.out.println("-----核心业务:保存!!!------");
}
}
编写AOP代理类
package cn.itcast.e_aop_anno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect // 指定当前类为切面类
public class Aop {
// 指定切入点表单式: 拦截哪些方法; 即为哪些类生成代理对象
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))")
public void pointCut_(){
}
// 前置通知 : 在执行目标方法之前执行
@Before("pointCut_()")
public void begin(){
System.out.println("开始事务/异常");
}
// 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】
@After("pointCut_()")
public void after(){
System.out.println("提交事务/关闭");
}
// 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】
@AfterReturning("pointCut_()")
public void afterReturning() {
System.out.println("afterReturning()");
}
// 异常通知: 当目标方法执行异常时候执行此关注点代码
@AfterThrowing("pointCut_()")
public void afterThrowing(){
System.out.println("afterThrowing()");
}
// 环绕通知:环绕目标方式执行
@Around("pointCut_()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕前....");
pjp.proceed(); // 执行目标方法
System.out.println("环绕后....");
}
}
App.java
package cn.itcast.e_aop_anno;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
ApplicationContext ac =
new ClassPathXmlApplicationContext("cn/itcast/e_aop_anno/bean.xml");
// 目标对象有实现接口,spring会自动选择“JDK代理”
@Test
public void testApp() {
IUserDao userDao = (IUserDao) ac.getBean("userDao");
System.out.println(userDao.getClass());//$Proxy001
userDao.save();
}
// 目标对象没有实现接口, spring会用“cglib代理”
@Test
public void testCglib() {
OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
System.out.println(orderDao.getClass());
orderDao.save();
}
@Deprecated
// 共性问题:如果目标对象有实现接口,在从容器中获取目标对象的时候,只能通过接口接收对象。
public void testApp2() {
// 错误代码: 只能用接口接收
UserDao userDao = (UserDao) ac.getBean("userDao");
System.out.println(userDao.getClass());//$Proxy001
userDao.save();
}
@Test
public void testGetObj() throws Exception {
OrderDao orderDao1 = (OrderDao) ac.getBean("orderDao");
OrderDao orderDao2 = (OrderDao) ac.getBean("orderDao");
System.out.println(orderDao1);
System.out.println(orderDao2);
}
}
bean.xml
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.itcast.e_aop_anno"></context:component-scan>
<!-- 开启aop注解方式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
第一个test:
class cn.itcast.e_aop_anno.UserDao
—–核心业务:保存!!!——
第二个test:
class cn.itcast.e_aop_anno.OrderDao
EnhancerByCGLIB2235e357
环绕前….
开始事务/异常
—–核心业务:保存!!!——
环绕后….
提交事务/关闭
afterReturning()
第三个test:
这是不行的
第四个test:
cn.itcast.e_aop_anno.OrderDao@6db33c
cn.itcast.e_aop_anno.OrderDao@1263db