第二章Spring框架 注解 AOP
0.Spring中使用DI注入复杂类型
准备工作:
public class CollectionBean { private Object[] arr; private List list; // list private Map map; private Properties pro; public Object[] getArr() { return arr; } public void setArr(Object[] arr) { this.arr = arr; } |
---|
0.1.Array数组类型
往数组注入单个值
<< span="">bean name="cb" class="com.shop.test.CollectionBean"> << span="">property name="arr" value="杰克">property>bean> |
---|
@Test public void fun1() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); CollectionBean bean = (CollectionBean) ac.getBean("cb"); System.out.println(bean); } |
---|
往数组注入多个值
<< span="">property name="arr"> << span="">array> << span="">value>杰克value> << span="">value>旺财value> << span="">ref bean="user3"/> array>property> |
---|
@Test public void fun1() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); CollectionBean bean = (CollectionBean) ac.getBean("cb"); System.out.println(bean); } |
---|
0.2.List 集合
往list注入单个值
<< span="">bean name="cb2" class="com.shop.test.CollectionBean"> << span="">property name="list" value="小黄">property>bean> |
---|
@Test public void fun2() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); CollectionBean bean = (CollectionBean) ac.getBean("cb2"); System.out.println(bean); } |
---|
注入多个值
<< span="">property name="list"> << span="">list> << span="">value>旺财value> << span="">value>阿黄value> << span="">value>潘金莲value> << span="">ref bean="user3"/> list> property> |
---|
@Test public void fun2() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); CollectionBean bean = (CollectionBean) ac.getBean("cb2"); System.out.println(bean); } |
---|
0.3.Map
<< span="">bean name="cb3" class="com.shop.test.CollectionBean"><< span="">property name="map"> << span="">map> << span="">entry key="url" value="http://localhost:8080">entry> << span="">entry key="car" value-ref="car">entry> << span="">entry key-ref="user" value-ref="user3">entry> map>property>bean> |
---|
@Test public void fun3() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); CollectionBean bean = (CollectionBean) ac.getBean("cb3"); System.out.println(bean); } |
---|
0.4.Properties
<< span="">bean name="cb4" class="com.shop.test.CollectionBean"><< span="">property name="pro"> << span="">props> << span="">prop key="url">http://localhost:3306prop> << span="">prop key="name">旺财prop> props>property>bean> |
---|
@Test public void fun4() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); CollectionBean bean = (CollectionBean) ac.getBean("cb4"); System.out.println(bean); } |
---|
2.AOP
2.1.AOP概述(掌握)
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
经典应用:事务管理、性能监视、安全检查、缓存 、日志等
Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,
AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
2.2.AOP思想简单分析(重点)
画图分析
2.3.AOP中专业术语(重点)
1.Target(目标类):需要被代理的类。例如:ProductService
2.joinPoint (连接点):所谓连接点,就是那些可能被spring拦截的点(方法)
3.pointCut(切入点):已经被增强的连接点(方法)
4.advice(通知/增强):那些增强的代码
5.weaving(织入):是指把增强advice应用到目标对象target来创建新的代
(proxy)的过程
6.poxy:代理类
7.Aspectj(切面):切入点pointcut和通知advice的结合
2.4.Spring中使用AOP(掌握)
2.4.1.导入架包
2.4.1.1.核心包
2.4.1.2.Spring中AOP包
2.4.1.3.第三方AOP包
spring-framework-3.0.2.RELEASE-dependenciesorg.aopalliancecom.springsource.org.aopalliance1.0.0com.springsource.org.aopalliance-1.0.0.jar
spring-framework-3.0.2.RELEASE-dependenciesorg.aspectjcom.springsource.org.aspectj.weaver1.6.8.RELEASEcom.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
最终jar图:
2.4.2.导入约束
完整约束
xml version="1.0" encoding="UTF-8"?><< span="">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 "> |
---|
2.4.2.准备目标类(target)
2.4.3.准备通知(增强)
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("出现异常,也会继续执行"); }} |
---|
2.4.4.织入
将通知(增强)织入到目标类中
2.4.4.1.配置目标类
<< span="">bean name="productservice" class="com.shop.aa.ProductService">bean> |
---|
2.4.4.2.配置通知
<< span="">bean name="myadvice" class="com.shop.aa.MyAadvice">bean> |
---|
2.4.4.3.织入配置
<< span="">bean name="productservice" class="com.shop.weaving.ProductService">bean> << span="">bean name="myadvice" class="com.shop.weaving.MyAdvice">bean> << span="">aop:config > << span="">aop:pointcut expression="execution(public void com.shop.weaving.ProductService.addProduct())" id="pc"/> << span="">aop:aspect ref="myadvice"> << span="">aop:before method="before" pointcut-ref="pc"/> << span="">aop:after method="afterReturning" pointcut-ref="pc"/> << span="">aop:around method="around" pointcut-ref="pc"/> << span="">aop:after-throwing method="afterException" pointcut-ref="pc"/> << span="">aop:after method="after" pointcut-ref="pc"/> aop:aspect>aop:config>beans> |
---|
2.4.5.编写测试类
public class TestDemo1 { @Test public void test1() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); userService.addUser(); }} |
---|
观察打印结果:
2.5.切入点表达式详解
代码语言:javascript复制<< span="">aop:pointcut id="pc" expression="execution(public void com.shop.target.UserService.addUser())">aop:pointcut>
代码语言:javascript复制
public void com.shop.target.UserService.addUser() void com.shop.target.UserService.addUser() * com.shop.target.UserService.addUser() * com.shop.target.UserService.*User() * com.shop.target.UserService.*(..) * com.shop.target.*Service.*(..) * com.shop.target..*Service.*(..) |
---|
2.6.通知详解(advice)
2.6.1.通知介绍
1.前置通知 (before)
l(目标方法运行之前调用)
2.后置通知 (after-returning)
l(目标方法运行之后调用)
l(如果出现异常则不会调用)
3.环绕通知 (around)
l在目标方法之前和之后都调用
4.异常拦截通知(after-throwing)
l如果出现异常,就会调用
5.后置通知(最终通知)(after)
l目标方法运行之后调用
l(无论是否出现异常,都会被调用)
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("出现异常,也会继续执行"); }} |
---|
通知(增强)的类型:
1.前置通知
l在目标类的目标方法执行之前执行
l实用场景:可以对方法的参数来做校验
l配置文件信息:
2.后置通知
l在目标类的目标方法执行之后执行
l如果有异常则不会执行
l实用场景:可以修改方法的返回值
l在配置文件中编写具体的配置:
3.最终通知
l在目标类的目标方法执行之后执行
l如果有异常仍然会执行
l实用场景:释放资源
l在配置文件中编写具体的配置:
4.异常抛出通知
l在抛出异常时,执行该通知
l实用场景:包装异常的通知
l在配置文件中编写具体的配置:
5.环绕通知
l在目标类的目标方法执行前后都会去执行
l注意:实用环绕通知时,默认的目标方法不会去执行,需要ProceedingJoinPoint对来让目标对象的方法执行。
l在配置文件中编写具体的配置:
2.6.2.通知测试
afterException() 如果在代码运行过程中发生了异常,将会被此通知拦截
public class MyAdvice { public void afterException() { System.out.println("不好了,出事情了"); } } |
---|
<< span="">aop:config> << span="">aop:pointcut id="pc" expression="execution(public void com.shop.target.UserService.addUser())">aop:pointcut> << span="">aop:aspect ref="myAdvice"> << span="">aop:after-throwing method="afterException" pointcut-ref="pc">aop:after-throwing> aop:aspect>aop:config> |
---|
打印观察测试:
后置通知 (after-returning)
n(目标方法运行之后调用)
n(如果出现异常则不会调用)
后置通知(最终通知)(after)
u目标方法运行之后调用
u(无论是否出现异常,都会被调用)
观察打印结果:
2.6.3.通知(advice)参数
Joinpoint参数(重点)
n每种通知类型,在方法名()内部还可以接收一个参数,该参数的类型是Joinpoint
n使用Joinpoint可以看到一些东西
ØgetTarget() 获得被代理的目标对象
ØgetSignature().getName() 获取被代理目标类 中的目标方法
示例代码:
3.注解(Annotation)
3.1.注解介绍
注解是JDK1.5之后才有的新特性
JDK1.5之后内部提供的三个注解
@Deprecated 意思是“废弃的,过时的”
@Override 意思是“重写、覆盖”
@SuppressWarnings 意思是“压缩警告”
3.2.Spring框架中注解操作
在Spring框架注解操作一共针对以下几方面:
IOC 控制反转
DI 依赖注入
AOP 面向切面
注解存在意义:
使用注解取代xml配置!!!!!!!!!!
3.2.1.注解实现IOC
3.2.1.1.添加xml配置
建议从下往上翻阅
3.2.1.2.给对象添加注解
@Component
格式:
@Component(value=”bean对象名称”)
@Componment(“bean对象名称”)
3.2.1.3.测试
@Test public void fun1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = (User) context.getBean("user"); System.out.println(user); } |
---|
该错误注意
注意:使用注解开发,必须要开启注解扫描,让spring容器知道,你使用的是注解方式
如何开启spring注解扫描??
<< span="">context:component-scan base-package="com.shop.domain">context:component-scan> |
---|
观察结果:
注意了:新版本的spring想实现注解效果,需要添加一个
【开发小结】:
1.使用注解方式开发,必须要先开启注解扫描,否则直接报错
2.Spring4以上版本,玩儿注解,需要添加aop包,目前课上使用的最新Spring5.1.2
3.2.1.4.IOC中其它注解介绍
1.@Componment(作用在类上)
2.Spring中提供@Componment的三个衍生注解(目前功能是一致的)
* @Controller –作用在WEB层
* @Service - 作用在业务层
* @Repository – 作用于持久层(dao层)
说明:使用这三个注解是为了让开发人员更明白注解类本身的用途,Spring后续版本可能会对其增强
[开发小结]:
如果是为了单纯的创建Bean,使用@Componment
在项目开发中三层使用 @Controller(web层) @Service(service层) @Repository(dao层)
@Scope(scopeName="prototype")
@Scope(scopeName="singleton")
3.2.2.注解实现DI
说明:使用注解方式,可以不用提供set方法
1. 如果注入的是普通类型,可以使用Value注解
2.如果注入的是对象类型,可以使用如下注解
@AutoWired – 默认按类型自动装配
@Component(value = "car")public class Car { private String name; private String color; public String getName() { return name; } |
---|
@Repository(value="userservice")public class User { @Value(value="jack") private String name; private int age; @Autowired private Car car; public String getName() { return name; } |
---|
@Qualifier - 强制使用名称注入
<< span="">bean name="car2" class="com.shop.zhujie.Car"> << span="">property name="name" value="小卡车">property> << span="">property name="color" value="灰色">property>bean> |
---|
@Repository(value="userservice")public class User { @Value(value="jack") private String name; private int age; @Autowired @Qualifier(value="car2") private Car car; |
---|
说明:AutoWired和Qualifier都是spring框架提供的
@Resource是Java程序提供的,只不过被spring框架所支持 - 相当于@AutoWired和@Qualifier一起使用
public class User { @Value(value="jack") private String name; private int age; @Resource(name="car2") private Car car; |
---|
3.2.3.注解实现AOP
3.2.3.1.导入jar包(AOP架包)
n先引入Spring框架开发的基本开发包
n再引入Spring框架的AOP的开发包
* spring的传统AOP的开发的包
* spring-aop-4.2.4.RELEASE.jar
* com.springsource.org.aopalliance-1.0.0.jar
* aspectJ的开发包
* com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
* spring-aspects-4.2.4.RELEASE.jar
3.2.3.2.导入xml
xml version="1.0" encoding="UTF-8"?><< span="">beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> |
---|
3.2.3.3.编写目标接口和目标实现类
目标类
public class ProductService { public void addProduct() { System.out.println("添加商品..."); } public void updateProduct() { System.out.println("更新商品............."); } public void deleteProduct() { System.out.println("删除商品"); }} |
---|
通知(增强类)
@Aspectpublic class MyAdvice {@Before(value="execution(public void com.shop.weaving.ProductService.addProduct())") public void before() { System.out.println("开启事务"); } public void afterReturning() { System.out.println("提交事务。。。"); } |
---|