Spring第二天继续,今天要学习的是Spring的IOC的注解方式和Spring的AOP开发(XML)
1.Spring的IOC注解方式开发
1.1Spring的IOC注解开发入门
1.1.1创建Web项目引入Jar包
在Spring4的版本中,除了引入基本的开发包以外,还需要引入aop的包。
1.1.2引入Spring的配置文件
在src下创建applicationContext.xml,使用注解开发需要引入context的约束。
代码语言:javascript复制<?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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
1.1.3创建接口和实现类
接口:
代码语言:javascript复制package com.albertyy.spring.demo1;
/**
* 用户管理DAO层接口
* @author yxy
*
*/
publicinterface UserDAO {
publicvoid save();
}
实现类:
代码语言:javascript复制package com.albertyy.spring.demo1;
/**
* 用户管理DAO层实现类
* @author yxy
*
*/
publicclass UserDAOImpl implements UserDAO {
@Override
publicvoid save() {
System.out.println("UserDAOImpl执行了...");
}
}
1.1.4开启Spring的组件扫描
代码语言:javascript复制<!-- Spring的IOC的注解入门 -->
<!-- 使用IOC注解开发,配置组件扫描(那些包下的类使用IOC注解) -->
<context:component-scan base-package="com.albertyy.spring.demo1"></context:component-scan>
1.1.5在类上添加注解
代码语言:javascript复制package com.albertyy.spring.demo1;
import org.springframework.stereotype.Component;
/**
* 用户管理DAO层实现类
* @author yxy
*
*/
@Component("userDao") //相当于<bean name="userDAO"class="com.albertyy.spring.demo1.UserDAOImpl" />
publicclass UserDAOImpl implements UserDAO {
@Override
publicvoid save() {
System.out.println("UserDAOImpl执行了...");
}
}
1.1.6编写测试类
代码语言:javascript复制 @Test
/**
* Spring的IOC注解方式
*/
publicvoid demo2(){
//创建Spring的工厂
ApplicationContextapplicationContext = newClassPathXmlApplicationContext("applicationContext.xml");
UserDAOuserDAO = (UserDAO) applicationContext.getBean("userDao");
userDAO.save();
}
1.1.7注解方式设置属性的值
使用注解方式设置值可以没有set方法。如果属性有set方法,需要将属性注入的注解添加到set方法上,如果属性没有set方法,将属性注入的注解添加到属性上。
代码语言:javascript复制/**
* 用户管理DAO层实现类
* @author yxy
*
*/
@Component("userDao") //相当于<bean name="userDAO"class="com.albertyy.spring.demo1.UserDAOImpl" />
publicclass UserDAOImpl implements UserDAO {
@Value("李四")
private String name;
// @Value("张三")
// publicvoid setName(String name) {
// this.name= name;
// }
@Override
publicvoid save() {
System.out.println("UserDAOImpl执行了..." name);
}
1.2Spring的IOC注解的详解
1.2.1IOC注解@component
- 修饰一个类,将这个类交给spring管理这个注解有三个衍生类:
- @Controller:web层
- @service:service层
- @Repository:dao层
@Repository、@Service 和 @Controller。在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这3个注释分别和持久层、业务层和控制层(Web 层)相对应。
1.2.2属性注入注解
- 普通属性
- @Value:设置普通属性的值
- 对象类型属性
- @Autowired:设置对象类型的属性的值,但是是按照类型完成属性注入的。
- 因为我们习惯是按名字完成注入:所以就必须让!@Autowired和@Qualifier(value=“需要注解的对象的注解名字”)一起使用,完成按照名称属性注入。
- 可以用@Resource来替代上面的俩,来完成对象的注解。
@Service("userService")
publicclass UserServiceImpl implements UserService {
//注入Dao
// @Autowired
// @Qualifier("userDao")
@Resource(name="userDao")
private UserDao userDao;
@Override
publicvoid save() {
userDao.save();
System.out.println("UserService执行了、、、、。。。");
}
}
1.2.3Bean的其他注解
- 生命周期相关的注解(了解)
- @PostConstruct:相当于init-method,初始化方法
- @PreDestroy :相当于destroy-method,销毁方法
- Bean作用范围的注解
- scope:Bean的作用范围
- singleton :默认的,Spring会采用单例模式创建这个对象。
- prototype :多例模式。(Struts2和Spring整合一定会用到)
- request :应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。
- session :应用在web项目中,Spring创建这个类以后,将这个类存入到session范围中。
- globalsession :应用在web项目中,必须在porlet环境下使用。但是如果没有这种环境,相对于session。
1.2.4IOC的XML和注解开发的比较
适用场景:
u xml:可以适用任何场景 。
l 好处:结构清晰,后期方便维护
u 注解:有些地方用不了,比如:这个类,不是自己提供的 。
l 好处:开发方便
1.2.5 XML和注解混合使用
- XML管理Bean,注解完成属性注入。
<!-- 在没有扫描的情况下,使用属性注入的注解:@Resource,@Value,@Autowired,@Qualifier-->
<context:annotation-config></context:annotation-config>
2.Spring的AOP的XML开发
2.1什么是Aop
在软件业,AOP为AspectOriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。原有项目功能上,通过aop去添加新的功能,这些功能是建立在原有的功能基础上的,而且不会修改原来代码以及逻辑。
打个不恰当的比方,这就好像我们吃汉堡,想要加个牛排,直接把牛排加在里面就行了,而不会影响原来汉堡里面的东西,利用Aop思想也是同样的道理,我们想要在程序中新加一个功能,就像在汉堡中加上一个牛排,不会影响原来的程序。
2.2Spring底层的Aop实现原理
l 动态代理
n JDK动态代理:只能对实现了接口的类产生代理
n Cglib动态代理:对没有实现接口的类产生代理对象,生成子类对象。
反射用的shiClass 动态代理用的是Proxy
2.3Spring的Aop应用场景
一般来说:打印日志,还有短信通知啊,权限验证等,都可以使用aop来实现。
2.4Spring的Aop的开发(AspectJ的XML的方式)
2.4.1Spring的AOP简介
AOP思想最早是由AOP联盟组织提出的,Spring是使用这种思想最好的框架。AspectJ是AOP的一个很悠久的实现框架,它能够和 Java 配合起来使用。Spring有自己的Aop实现,但比较繁琐,所以引入AspectJ作为自己的店Aop开发方式。
2.4.2 AOP开发中的术语
- 连接点Joinpoint:可以拦截到的点 。
- 切入点Poincut:真正被拦截到的点 。
- 通知Advice:通知,方法层面的增强。
- 引介Introduction:类层面的增强。
- 目标Target:被增强的对象。
- 织入Weaviong:将通知应用(Advice)到目标(Target)的过程 将权限校验的方法的代码应用到UserDao的save方法的过程就是织入。
- 代理Proxy:被增强后产生的代理对象。
- 切面Aspect:多个通知和多个切入点的组合,比如拦截器。
2.5Spring的Aop的入门(AspectJ的XML的方式)
2.5.1创建web项目,引入jar包
- 引入基本开发包
- 引入aop开发的相关的jar包
2.5.2引入Spring的配置文件
引入aop的约束
代码语言:javascript复制<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
2.5.3编写目标类并完成配置
目标类:
代码语言:javascript复制package com.albertyy.demo1;
publicclass ProductDaoImpl implements ProductDao {
@Override
publicvoid save() {
System.out.println("保存");
}
@Override
publicvoid update() {
System.out.println("修改");
}
@Override
publicvoid delete() {
System.out.println("删除");
}
@Override
publicvoid find() {
System.out.println("查找");
}
}
配置:
代码语言:javascript复制<!-- 配置目标对象,即被增强的对象 -->
<bean id="productDao" class="com.albertyy.demo1.ProductDaoImpl"></bean>
2.5.4编写测试类
- Spring整合Junit单元测试
引入Spring-test的jar包
代码编写:
代码语言:javascript复制package com.albertyy.demo1;
/*
* aop的入门
*/
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
publicclass Demo1 {
@Resource(name="productDao")
private ProductDao pd;
@Test
publicvoid demo1() {
pd.delete();
pd.save();
pd.find();
pd.update();
}
}
2.5.5编写一个切面类
- 编写切面
package com.albertyy.demo1;
/**
*
* 项目名称:Spring_AOP
* 类名称:MyAspectXML
* 类描述:切面类
* 创建人:yangyangyang
* 创建时间:2018年12月4日下午6:11:42
* 修改人:yangyangyang
* 修改时间:2018年12月4日下午6:11:42
* 修改备注:
* @version
*
*/
publicclass MyAspectXML {
publicvoid checkPri(){
System.out.println("-------权限校验------");
}
}
- 配置切面:将切面类交给Spring管理
<!-- 将切面类交给Spring管理 -->
<bean id="myAspect" class="com.albertyy.demo1.MyAspectXML"></bean>
2.5.6通过AOP配置实对目标类产生代理
代码语言:javascript复制<!-- 通过AOP配置对目标类产生代理 -->
<aop:config>
<!-- 表达式配置哪些类的那些方法需要进行增强 -->
<aop:pointcut expression="execution(* com.albertyy.demo1.ProductDaoImpl.save(..))"id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
2.6Spring的通知类型
2.6.1前置通知:在目标方法执行之前进行操作
- 前置通知:可以获得切入点的信息。
- 在切面类的前置通知的方法内传入一个传入参数(JoinPoint jp)然后打印就可以获得切入点的信息。
publicclass MyAspectXML {
/*
* 前置通知
*/
publicvoid checkPri(JoinPoint jp){
System.out.println("-------权限校验------" jp);
}
}
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>
2.6.2后置通知:在目标方法执行之后进行操作
- 后置通知:可以获得方法的返回值。
- 在切面类的后置通知的方法内传入一个Object类型的以配置文件中返回值returning为名字的参数打印即可获得切入点的返回值。
/*
* 后置通知
*/
publicvoid writeLog(Object result){
System.out.println("-------日志记录------" result);
}
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<!-- 前置通知 -->
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="writeLog" pointcut-ref="pointcut2"returning="result"/>
</aop:aspect>>
2.6.3环绕通知:在目标方法执行之前和之后进行操作
- 环绕通知:阻止目标方法的执行。
/*
* 环绕通知:性能监控
*/
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("-----环绕前通知-------");
Objectb= joinPoint.proceed();
System.out.println("-----环绕后通知-------");
returnb;
}
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3" />
2.6.4异常抛出通知:在程序抛出异常的时候进行操作
代码语言:javascript复制/*
* 异常抛出通知
*/
publicvoid afterThrowing(Throwable ex){
System.out.println("-----异常抛出通知-------" ex.getMessage());
}
<!-- 异常抛出通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
2.6.5最终通知:无论是否有异常,都执行(相当于try-catch中的finally)
代码语言:javascript复制//最终通知:相当于finally
publicvoid after(){
System.out.println("-----最终通知");
}
<!-- 最终通知 -->
<aop:after method="after" pointcut-ref="pointcut4"/>
2.6.6引介通知(略)
2.7Spring切入点的表达式语法
- 基于execution的函数完成的
- 语法:
- [访问修饰符] 方法返回值 包名.类名.方法名(参数) 。
- public voidcom.spring.CustomerDao.save(..) 返回值为void类型在包com.spring下CustomerDao类中的切入点save()方法,传入的切入点的参数为任意类型。
- *.*.*Dao.save(..) 任意返回值,任意包下的名字下的Dao类的save方法,传入的切入点的参数为任意类型。
- com.spring.CustomerDao .save(..)返回值为任意类型在包com.spring下CustomerDao类及其子类的切入点save(),传入的切入点的参数为任意类型。
- com.spring.*.*(..)返回值为任意类型在包com.spring下任意类中的任意切入点 切入点传入的参数为任意类型。
源码链接:链接: https://pan.baidu.com/s/1lH8HPS1aalBSYqhMmDZjnQ提取码: ihip