Spring框架基础2
Posted XDZY
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架基础2相关的知识,希望对你有一定的参考价值。
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(); } }
以上是关于Spring框架基础2的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段