java框架之Spring(2)-注解配置IOC&AOP配置
注解配置IoC
准备
1、要使用注解方式配置 IoC,除了之前引入的基础 jar 包,还需要引入 spring-aop 支持包,如下:

2、在 applicationContext.xml 中引入 context 约束:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!--配置文件约束在 spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html 下可以找到-->
</beans>
简单使用
package com.zze.dao;
public interface UserDao {
void save();
}
com.zze.dao.UserDao
package com.zze.dao.impl;
import com.zze.dao.UserDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 实例化当前类并将其交给 Spring 管理
* 相当于在配置文件中配置 <bean id="userDao" class="com.zze.dao.impl.UserDaoImpl"/>
*/
@Component("userDao")
public class UserDaoImpl implements UserDao {
/*
给属性注入值
*/
@Value("张三")
private String name;
/*
如果提供了 set 方法,则可在 set 方法上加上注解
*/
// @Value("张三")
// public void setName(String name) {
// this.name = name;
// }
@Override
public void save() {
System.out.println("from UserDaoImpl.save()" + name);
}
}
com.zze.dao.impl.UserDaoImpl : 使用注解
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!--使用 IoC 注解开发,配置注解扫描的包(哪些包下使用了 IoC 注解)-->
<context:component-scan base-package="com.zze.dao"/>
</beans>
applicationContext.xml : 配置注解扫描的包
@Test
public void test1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
test
常用注解
@Component:实例化注解
修饰一个类,将这个类实例交给 Spring 管理。
这个注解有三个衍生注解(功能相同):
- @Controller:修饰 web 层的类。
- @Service:修饰 service 层的类。
- @Repository:修饰 dao 层的类。
属性注入注解
普通类型的属性注入:
- @Value:设置普通属性的值。
对象类型的属性注入:
- @Autowired:设置对象类型属性的值。
默认情况下是按照类型匹配完成属性注入,如果想按照名称匹配完成属性注入,可以同时再使用一个注解 @Qualifier 来指定要注入对象的名称。
@Autowired @Qualifier("userDao") private UserDao userDao;例:
- @Resource:根据对象名称匹配完成属性注入。
@Resource(name = "userDao") private UserDao userDao;
例:
生命周期相关注解
- @PostConstruct:修饰一个方法,让其在实例化时执行,相当于在 bean 标签中指定 init-method 。
- @PreDestroy:修饰一个方法,让其在实例销毁之前执行,相当于在 bean 标签中指定 destroy-method。
@Scope:作用范围注解
修饰一个类,指定其作用范围。
singleton :默认值,Spring 会采用单例模式创建这个对象。
prototype :多例的。
request :应用在 web 项目中,Spring 创建这个类对象后,将这个对象存放到 request 范围中。
session :应用在 web 项目中,Spring 创建这个类对象后,将这个对象存放的 session 范围中。
globalsession :应用在 web 项目中,必须在 porlet 环境下使用。
总结
IoC的XML和注解方式开发相比较
XML 方式:结构清晰,维护方便,适用于任意场景。
注解方式:简易开发,当一个类不是自己编写而是由第三方提供时,不可以使用。
XML方式和注解方式整合开发
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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:annotation-config/>
<bean name="userService" class="com.zze.service.impl.UserServiceImpl"/>
<bean name="userDao" class="com.zze.dao.impl.UserDaoImpl"/>
</beans>
applicationContext.xml
package com.zze.service.impl;
import com.zze.dao.UserDao;
import com.zze.service.UserService;
import javax.annotation.Resource;
public class UserServiceImpl implements UserService {
@Resource(name = "userDao")
private UserDao userDao;
@Override
public void save() {
System.out.println("from UserServiceImpl.save()");
userDao.save();
}
}
com.zze.service.impl.UserServiceImpl
AOP配置
概述
在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP 思想最早是由 AOP 联盟组织提出,Spring 是目前使用这种思想最好的框架。
Spring 本身有自己的 AOP 实现方式,但是非常繁琐。AspectJ 是一个 AOP 框架,Spring 后期引入了 AspectJ 用作自身 AOP 开发。
Spring中AOP实现原理:
Spring 底层是使用动态代理技术实现 AOP。当被代理类实现了接口,此时就会使用 JDK 动态代理方式生成代理对象。当被代理类未实现接口,此时 Spring 就会使用 Cglib 动态代理方式生成代理对象。
AOP相关术语
- 连接点(Joinpoint):
程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些点中的特定点就称为“连接点”。Spring 仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。连接点由两个信息确定:第一是用方法表示的程序执行点;第二是用相对点表示的方位。
通俗讲其实就是可以被拦截到的点(方法),增删改查方法都可以被拦截增强,这些方法就可以称为是连接点。
- 切入点(Pointcut):
每个程序类都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点,即连接点是程序类中客观存在的事物。AOP通过“切点”定位特定的连接点。连接点相当于数据库中的记录,而切点相当于查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。在Spring中,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件,Spring AOP的规则解析引擎负责切点所设定的查询条件,找到对应的连接点。其实确切地说,不能称之为查询连接点,因为连接点是方法执行前、执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,所以如果希望定位到具体连接点上,还需要提供方位信息。
通俗讲就是真正被拦截到的点(方法),如果在开发中只对 save 方法进行增强,那么 save 就称为是切入点。
- 增强、通知(Advice):
增强是织入到目标类连接点上的一段程序代码,在 Spring 中,增强除用于描述一段程序代码外,还拥有另一个和连接点相关的信息,这便是执行点的方位。结合执行点方位信息和切点信息,我们就可以找到特定的连接点。
通俗讲就是方法层面的增强,如果要使用 checkPermission 方法进行权限校验,那么 checkPermission 方法就称为是增强。
几种通知类型:- 前置通知:在目标方法执行之前进行的操作。
- 后置通知:在目标方法执行之后进行的操作。
- 环绕通知:在目标方法执行之前和之后进行的操作。
- 异常抛出通知:在程序出现异常时进行的操作。
- 最终通知:无论代码是否有异常,总是会执行。
- 目标对象(Target):
增强逻辑的织入目标类。如果没有 AOP,目标业务类需要自己实现所有逻辑,而在 AOP 的帮助下,目标业务类只实现那些非横切逻辑的程序逻辑,而性能监视和事务管理等这些横切逻辑则可以使用 AOP 动态织入到特定的连接点上。
通俗讲就是指被增强的类,如果对 UserDao 类进行增强,那么 UserDao 类就是目标对象。
- 引介(Introduction):
引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过 AOP 的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
通俗讲就是类层面的增强。
- 织入(Weaving):
织入是将增强添加对目标类具体连接点上的过程。AOP 像一台织布机,将目标类、增强或引介通过 AOP 这台织布机天衣无缝地编织到一起。根据不同的实现技术,AOP有三种织入的方式:
a、编译期织入,这要求使用特殊的Java编译器。
b、类装载期织入,这要求使用特殊的类装载器。
c、动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。通俗讲就是将通知(Advice)应用到目标对象(Target)的过程。
- 代理(Proxy):
一个类被 AOP 织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。
通俗讲就是最后返回的代理对象。
- 切面(Aspect):
切面由切入点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP 就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
通俗讲就是切入点与通知的组合。
XML方式
1、导包,除了要引入 6 个基础 jar 包外,还需引入如下 jar 包:

2、编写切面类:
package com.zze.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 切面类
*/
public class MyAspect {
public void before() {
System.out.println("前置通知");
}
public void afterReturning(Object result) {
System.out.println("后置通知" + result);
}
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前");
joinPoint.proceed();
System.out.println("环绕通知后");
}
public void afterThrowing(Throwable ex) {
System.out.println("异常抛出通知" + ex);
}
public void after(){
System.out.println("最终通知");
}
}
com.zze.aspect.MyAspect
3、编写目标类:
package com.zze.dao;
public interface UserDao {
public void save();
public Boolean delete();
public void list();
public void update();
}
com.zze.dao.UserDao
package com.zze.dao.impl;
import com.zze.dao.UserDao;
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("保存操作 from com.zze.dao.impl.UserDaoImpl.save()");
}
public Boolean delete() {
System.out.println("删除操作 from com.zze.dao.impl.UserDaoImpl.delete()");
return true;
}
public void list() {
System.out.println("查询操作 from com.zze.dao.impl.UserDaoImpl.list()");
int i = 1 / 0;
}
public void update() {
System.out.println("修改操作 from com.zze.dao.impl.UserDaoImpl.update()");
}
}
com.zze.dao.impl.UserDaoImpl
4、配置 applicationContext.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" 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">
<!--配置目标对象-->
<bean name="userDao" class="com.zze.dao.impl.UserDaoImpl" />
<!--配置切面类,将切面类交给 Spring 管理-->
<bean name="myAspect" class="com.zze.aspect.MyAspect"/>
<!--通过 AOP 配置对目标类代理-->
<aop:config>
<!--
表达式配置使用哪些方法类增强哪些类
语法:
[访问修饰符] 方法返回值 包名.类名.方法名(参数)
* 表示通配符
参数位置使用 .. 匹配任意参数
-->
<aop:pointcut id="pc1" expression="execution(* com.zze.dao.UserDao.save(..))"/>
<aop:pointcut id="pc2" expression="execution(* com.zze.dao.UserDao.delete(..))"/>
<aop:pointcut id="pc3" expression="execution(* com.zze.dao.UserDao.update(..))"/>
<aop:pointcut id="pc4" expression="execution(* com.zze.dao.UserDao.list(..))"/>
<!--配置切面-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before pointcut-ref="pc1" method="before"/>
<!--后置通知-->
<aop:after-returning pointcut-ref="pc2" method="afterReturning" returning="result"/>
<!--环绕通知-->
<aop:around pointcut-ref="pc3" method="around"/>
<!--异常抛出通知-->
<aop:after-throwing pointcut-ref="pc4" method="afterThrowing" throwing="ex"/>
<!--最终通知-->
<aop:after pointcut-ref="pc4" method="after"/>
</aop:aspect>
</aop:config>
</beans>
5、测试:
package com.zze.test;
import com.zze.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test{
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
userDao.save();
userDao.delete();
userDao.update();
userDao.list();
/*
前置通知
保存操作 from com.zze.dao.impl.UserDaoImpl.save()
删除操作 from com.zze.dao.impl.UserDaoImpl.delete()
后置通知true
环绕通知前
修改操作 from com.zze.dao.impl.UserDaoImpl.update()
环绕通知后
查询操作 from com.zze.dao.impl.UserDaoImpl.list()
最终通知
异常抛出通知java.lang.ArithmeticException: / by zero
*/
}
}
这里使用了 Spring 整合 JUnit 测试,需要额外导入 spring-test 包。
注解方式
1、导包,和 XML 配置 AOP 时相同,如下:

2、编写目标类:
package com.zze.dao;
public class UserDao {
public void save() {
System.out.println("保存操作 from com.zze.dao.impl.UserDao.save()");
}
public Boolean delete() {
System.out.println("删除操作 from com.zze.dao.impl.UserDao.delete()");
return true;
}
public void list() {
System.out.println("查询操作 from com.zze.dao.impl.UserDao.list()");
int i = 1 / 0;
}
public void update() {
System.out.println("修改操作 from com.zze.dao.impl.UserDao.update()");
}
}
com.zze.dao.UserDao
3、编写切面类并使用注解配置:
package com.zze.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* 切面类
*/
@Aspect
public class MyAspect {
/**
* 定义一个切入点表达式,在下方可引用
*/
@Pointcut("execution(* com.zze.dao.UserDao.list(..))")
public void pc1() {
}
/**
* 前置通知
*/
@Before(value = "execution(* com.zze.dao.UserDao.save(..))")
public void before() {
System.out.println("前置通知");
}
/**
* 后置通知
*/
@AfterReturning(value = "execution(* com.zze.dao.UserDao.delete(..))", returning = "result")
public void afterReturning(Object result) {
System.out.println("后置通知" + result);
}
/**
* 环绕通知
*/
@Around(value = "execution(* com.zze.dao.UserDao.update(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前");
joinPoint.proceed();
System.out.println("环绕通知后");
}
/**
* 异常抛出通知
*/
@AfterThrowing(value = "pc1()", throwing = "ex")
public void afterThrowing(Throwable ex) {
System.out.println("异常抛出通知" + ex);
}
/**
* 最终通知
*/
@After(value = "pc1()")
public void after() {
System.out.println("最终通知");
}
}
com.zze.aspect.MyAspect
4、配置 applicationContext.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" 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">
<!--开启注解 AOP 开发-->
<aop:aspectj-autoproxy/>
<!--目标类-->
<bean name="userDao" class="com.zze.dao.UserDao"/>
<!--切面类-->
<bean name="myAspect" class="com.zze.aspect.MyAspect"/>
</beans>
5、测试:
package com.zze.test;
import com.zze.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo2 {
@Autowired
private UserDao userDao;
@Test
public void test() {
userDao.save();
userDao.delete();
userDao.update();
userDao.list();
/*
前置通知
保存操作 from com.zze.dao.impl.UserDao.save()
删除操作 from com.zze.dao.impl.UserDao.delete()
后置通知true
环绕通知前
修改操作 from com.zze.dao.impl.UserDao.update()
环绕通知后
查询操作 from com.zze.dao.impl.UserDao.list()
最终通知
异常抛出通知java.lang.ArithmeticException: / by zero
*/
}
}
java框架之Spring(2)-注解配置IOC&AOP配置的更多相关文章
- java框架之Spring(5)-注解驱动开发
准备 1.使用 maven 创建一个 java 项目,依赖如下: <dependency> <groupId>org.springframework</groupId&g ...
- Spring的注解学习(ioc,aop结合)
首先引入jar包 aspectjrt.jar aspectjweaver.jar 1.dao package com.dao; public interface OkpDao { public voi ...
- 基于纯Java代码的Spring容器和Web容器零配置的思考和实现(3) - 使用配置
经过<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(1) - 数据源与事务管理>和<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(2) - ...
- (转)使用Spring的注解方式实现AOP入门
http://blog.csdn.net/yerenyuan_pku/article/details/52865330 首先在Eclipse中新建一个普通的Java Project,名称为spring ...
- Spring的注解方式实现AOP
Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...
- 使用Spring的注解方式实现AOP
Spring对AOP的实现提供了很好的支持.下面我们就使用Spring的注解来完成AOP做一个例子. 首先,为了使用Spring的AOP注解功能,必须导入如下几个包.aspectjrt.jar,asp ...
- (转)使用Spring的注解方式实现AOP的细节
http://blog.csdn.net/yerenyuan_pku/article/details/52879669 前面我们已经入门使用Spring的注解方式实现AOP了,现在我们再来学习使用Sp ...
- SSM框架之Spring(3)IOC及依赖注入(基于注解的实现)
Spring(3)IOC及依赖注入(基于注解的实现) 学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样 的,都是要降低程序间的耦合.只是配置的形 ...
- atititt.java定时任务框架选型Spring Quartz 注解总结
atititt.java定时任务框架选型Spring Quartz 总结 1. .Spring Quartz (ati recomm) 1 2. Spring Quartz具体配置 2 2.1. 增 ...
随机推荐
- linux环境快速安装python3
之前在linux上安装python3的时候,为了让不影响linux环境原有的python2的环境,选择的方法都是下载对应的linux环境的python包,不过 这里需要注意的是,不要更改linux默认 ...
- macOS 下 PHPStorm + Xdebug 调试 Docker 环境中的代码
0x00 描述 宿主机是 mac mini,构建的项目在 docker 中,所以需要在 PHPStorm 上配置 Xdebug 进行远程代码调试. 0x01 环境 宿主机:macOS High Sie ...
- Elasticsearch 性能监控基础【转】
https://blog.csdn.net/yangwenbo214/article/details/74000458
- Git入门到高级系列1-git安装与基础命令
视频课程地址 腾讯课堂 为什么要进行项目文件的版本管理 代码备份和恢复 团队开发和协作流程 项目分支管理和备份 git 是什么? git是一个分布式的版本控制软件.版本控制是一种记录一个或若干文件内容 ...
- mac 环境变量
在 ~/.bash_profile 中添加一行: export PATH=$PATH:/usr/local/bin 其中,/usr/local/bin 为需要添加的 path 执行 source .b ...
- elasticsearch 一、环境配置
简介 ElasticSearch是一个开源的分布式搜索引擎,具备高可靠性,支持非常多的企业级搜索用例,是基于Lucene构建的.支持时间时间索引和全文检索.官网:http://www.elastics ...
- swiper4自动轮播切换手动触碰后停止踩坑——属性disableOnInteraction
swiper4轮播设置autoplay自动切换后,即默认设置: <script> var mySwiper = new Swiper('.swiper-container', { auto ...
- 鼠标交互插件threex.domevents介绍
threex.domevents是一个three.js的扩展库,支持3D场景的交互.和我们操作DOM树的事件相似,名称都是一样的.所以使用起来非常方便.另外他也提供了连接操作.单击网格可实现跳转功能. ...
- undo与redo
http://www.cnblogs.com/HondaHsu/p/3724815.html
- saltstack通过jinja模板,grains方式将配置的变量值写入到配置文件中?
需求描述: 在通过saltstack进行jinja模板获取值的时候,可以通过grains的方式,获取一些操作系统相关的信息,比如,OS,ip地址等,在这里演示下,做个记录. 演示: 1.修改sls文件 ...