Spring框架基础2

测试Spring的AOP思想和注解的使用

导包(在前面的基础上添加)

SpringAOP名词解释

AOP编程思想:横向重复代码,纵向抽取;就是说多个地方重复的代码可以抽取出来公用(过滤器等可以体现)
动态代理:动态代理可以体现AOP思想;对目标方法进行增强
SpringAOP开发:封装了动态代理代码(包括cglib代理),可以对任何类进行代理增强
Joinpoint(连接点):目标对象中,所有可以增强的方法
Pointcut(切入点):目标对象,已经增强的方法
Advice(通知/增强):增强的代码
Target(目标对象):被代理对象
Weaving(织入):将通知应用到切入点的过程
Proxy(代理):将通知织入到目标对象之后,形成代理对象
aspect(切面):切入点+通知

创建配置文件(如图由上至下)

<?xml version="1.0" encoding="UTF-8"?>
<!-- 使用某个标签之前要导入相应的约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "> <!-- 配置目标对象 -->
<bean name="userService" class="com.service.UserServiceImpl"></bean>
<!-- 配置通知对象 -->
<bean name="myAdvice" class="com.anno.MyAdvice"></bean>
<!-- 将通知织入目标对象,利用注解实现 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!-- 使用某个标签之前要导入相应的约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "> <!-- 配置目标对象 -->
<bean name="userServiceTarget" class="com.service.UserServiceImpl"></bean>
<!-- 配置通知对象 -->
<bean name="myAdvice" class="com.aspect.MyAdvice"></bean>
<!-- 将通知织入目标对象 -->
<aop:config>
<!-- 配置切入点,即需要加强功能的方法
public void com.service.UserServiceImpl.save()
void com.service.UserServiceImpl.save()
* com.service.UserServiceImpl.save()
* com.service.UserServiceImpl.*
* com.service.UserServiceImpl.*(..)
* com.service.*ServiceImpl.*(..)-->
<aop:pointcut id="pc" expression="execution(* com.service.*ServiceImpl.*(..))"/>
<aop:aspect ref="myAdvice">
<!-- 将myAdvice的before切入到UserServiceImpl.save() -->
<aop:before method="before" pointcut-ref="pc"/>
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc"/>
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd "> <!-- 扫描相应包下的类的所有注解 -->
<!-- 会扫描该包下的所有子孙类 -->
<context:component-scan base-package="com.bean"/> <bean name="car2" class="com.bean.Car">
<property name="name" value="玛莎拉蒂"/>
<property name="color" value="red"/>
</bean> </beans>

相应的实体类与接口

package com.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; /**
* @author: XDZY
* @date: 2018/9/5 23:38
* @description: 车辆实体类
*/
@Component("car")
public class Car {
@Value("兰博基尼")
private String name;
@Value("red")
private String color; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getColor() {
return color;
} public void setColor(String color) {
this.color = color;
} @Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
}
package com.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource; /**
* @author: XDZY
* @date: 2018/9/5 19:31
* @description: 用户实体类
* 通过注解获取对象
* "@Component("user")==<bean name="user" class="com.bean.User"/>"
*/
@Component("user")
//@Service("user")指定为service层
//@Controller("user")指定为web层
//@Repository("user")指定为dao层
//单例还是多例
//@Scope(scopeName = "singleton")
public class User {
//通过反射设置值,破坏了封装性
@Value("xdzy")
private String name;
@Value("15")
private int age; //自动配置car属性;但是有多个对象时,不知道获取哪个
//@Autowired
//指定哪个对象
//@Qualifier("car2")
//手动注解使用哪个car
@Resource(name = "car2")
private Car car; //创建对象前调用
@PostConstruct
public void init() {
System.out.println("初始化方法");
} //对象销毁前调用
@PreDestroy
public void destroy() {
System.out.println("销毁方法");
} public Car getCar() {
return car;
} public void setCar(Car car) {
this.car = car;
} public String getName() {
return name;
} //通过set设置值,推荐使用
@Value("xdzy")
public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
package com.service;

/**
* @author: XDZY
* @date: 2018/9/6 20:21
* @description:
*/
public interface UserService {
void save(); void del(); void update(); void find();
}
package com.service;

/**
* @author: XDZY
* @date: 2018/9/6 20:22
* @description:
*/
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("增加用户");
} @Override
public void del() {
System.out.println("删除用户");
} @Override
public void update() {
System.out.println("修改用户");
} @Override
public void find() {
System.out.println("查询用户");
}
}

JDK动态代理

package com.service;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; /**
* @author: XDZY
* @date: 2018/9/6 20:25
* @description: JDK动态代理
* 被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术
* 动态代理可对方法进行增强,如增加事务的打开与提交
* 个人理解:它是对service实现类里所有的方法进行了增强;
* 在不破坏原有结构的情况下,生成动态代理对象,对原有方法进行增强
*/
public class UserServiceProxyFactory implements InvocationHandler {
private UserService us; public UserServiceProxyFactory(UserService us) {
this.us = us;
} public UserService getUserServiceProxy() {
//生成动态代理
UserService userProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
UserServiceImpl.class.getInterfaces(),
this);
//返回一个动态代理对象
return userProxy;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("打开事务");
Object invoke = method.invoke(us, args);
System.out.println("提交事务");
return invoke;
}
}

Cglib代理

package com.service;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /**
* @author: XDZY
* @date: 2018/9/6 20:25
* @description: Cglib动态代理
* 可以对任何类生成代理,对目标对象进行继承代理
*/
public class UserServiceProxyFactory2 implements MethodInterceptor {
public UserService getUserServiceProxy() {
//生成代理对象
Enhancer en = new Enhancer();
//对谁进行代理
en.setSuperclass(UserServiceImpl.class);
//代理要做什么
en.setCallback(this);
//创建代理对象
UserService us = (UserService) en.create();
return us;
} @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//打开事务
System.out.println("打开事务");
//调用原有方法
Object returnValue = methodProxy.invokeSuper(o, objects);
//提交事务
System.out.println("提交事务");
return returnValue;
}
}

通知类

package com.anno;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*; /**
* @author: XDZY
* @date: 2018/9/7 08:23
* @description: 利用注解实现通知
* "@Aspect:表示该类是一个通知类
*/
@Aspect
public class MyAdvice {
//方便管理切入点
@Pointcut("execution(* com.service.*ServiceImpl.*(..))")
public void pc() {
} //配置通知,并指定织入到哪去
//前置通知:目标方法运行之前
@Before("MyAdvice.pc()")
public void before() {
System.out.println("前置通知");
} //后置通知(如果出现异常不会调用):之后
@AfterReturning("execution(* com.service.*ServiceImpl.*(..))")
public void afterReturning() {
System.out.println("后置通知(如果出现异常不会调用)");
} //环绕通知:之前之后
@Around("execution(* com.service.*ServiceImpl.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知之前部分");
//调用目标方法
Object proceed = pjp.proceed();
System.out.println("环绕通知之后部分");
return proceed;
} //异常拦截通知:出现异常调用
@AfterThrowing("execution(* com.service.*ServiceImpl.*(..))")
public void afterException() {
System.out.println("出现异常调用");
} //后置通知(无论是否出现异常都会调用):之后
@After("execution(* com.service.*ServiceImpl.*(..))")
public void after() {
System.out.println("后置通知(无论是否出现异常都会调用)");
}
}
package com.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

/**
* @author: XDZY
* @date: 2018/9/7 08:23
* @description: 通知
* 前置通知:目标方法运行之前
* 后置通知(如果出现异常不会调用):之后
* 环绕通知:之前之后
* 异常拦截通知:出现异常调用
* 后置通知(无论是否出现异常都会调用):之后
*/
public class MyAdvice {
//前置通知:目标方法运行之前
public void before() {
System.out.println("前置通知");
} //后置通知(如果出现异常不会调用):之后
public void afterReturning() {
System.out.println("后置通知(如果出现异常不会调用)");
} //环绕通知:之前之后
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知之前部分");
//调用目标方法
Object proceed = pjp.proceed();
System.out.println("环绕通知之后部分");
return proceed;
} //异常拦截通知:出现异常调用
public void afterException() {
System.out.println("出现异常调用");
} //后置通知(无论是否出现异常都会调用):之后
public void after() {
System.out.println("后置通知(无论是否出现异常都会调用)");
}
}

测试类

package com.test;

import com.service.UserService;
import com.service.UserServiceImpl;
import com.service.UserServiceProxyFactory;
import com.service.UserServiceProxyFactory2;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* @author: XDZY
* @date: 2018/9/6 09:32
* @description: 测试注解获取对象
* "@RunWith:可以帮助我们创建容器,这样xml地址改动,测试方法不用全部修改
* "@ContextConfiguration:指定容器位置
* 注意junit版本问题
*/
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration("classpath:resources/applicationContext.xml")
public class Demo1 {
/*@Resource(name = "user")
private User user; @Test
public void test(){
System.out.println(user);
}*/ //JDK动态代理
@Test
public void test1() {
UserService us = new UserServiceImpl();
UserServiceProxyFactory factory = new UserServiceProxyFactory(us);
UserService userProxy = factory.getUserServiceProxy();
userProxy.save(); //代理对象和被代理对象实现了相同的接口(false)
System.out.println(userProxy instanceof UserServiceImpl);
} //Cglib动态代理
@Test
public void test2() {
UserServiceProxyFactory2 factory = new UserServiceProxyFactory2();
UserService userProxy = factory.getUserServiceProxy();
userProxy.save(); //代理对象继承了被代理对象(true)
System.out.println(userProxy instanceof UserServiceImpl);
} //通知织入
@Test
public void test() {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("com/aop/applicationContext.xml");
//获取user对象
UserService userService = (UserService) ac.getBean("userServiceTarget");
userService.save();
} //注解通知织入
@Test
public void test4() {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("com/anno/applicationContext.xml");
//获取user对象
UserService userService = (UserService) ac.getBean("userService");
userService.save();
}
}

最新文章

  1. 简单的js菜单
  2. Android 媒体存储服务(一)
  3. [knowledge][basic][hardware] 内存的硬件结构(转)
  4. js事件代理
  5. ps 命令详解
  6. J2SE知识点摘记(二十二)
  7. 实现简单的ssh功能
  8. 【测试工程师面试】在BOSS直聘上和面试官的一问一答
  9. android矩阵详解
  10. vscode下Python设置参考
  11. [No000012F]WPF(7/7) - 样式,触发器和动画
  12. HDU 3951 Coin Game (简单博弈)
  13. SqlServer 查询死锁,杀死死锁进程*转载
  14. [译]新的CCSDS图像压缩推荐标准
  15. Android Paging库使用详解
  16. array_diff 不注意的坑
  17. Java调用http保留访问状态
  18. Learning Spatial Regularization with Image-level Supervisions for Multi-label Image Classification
  19. user-defined conversion
  20. hdu 5105(数学题)

热门文章

  1. Kudu 常见的几个应用场景
  2. XStream xml转java对象2
  3. oracle 找回被覆盖的存储过程
  4. js去除重复项
  5. 使用min-content实现容器宽度自适应于内部元素
  6. 编译Win32动态库工程的两个链接错误的解决
  7. Design Pattern -&gt;Bridge
  8. 菜鸟 学注册机编写之 Android app
  9. php 编译安装指导
  10. Windows下安装ElasticSearch及工具