Spring第二天:Spring的IOC的注解方式、Spring的AOP开发(XML)
Spring第二天继续,今天要学习的是Spring的IOC的注解方式和Spring的AOP开发(XML)
目录
2.4Spring的Aop的开发(AspectJ的XML的方式)
2.5Spring的Aop的入门(AspectJ的XML的方式)
2.6.5最终通知:无论是否有异常,都执行(相当于try-catch中的finally)
1.Spring的IOC注解方式开发
1.1Spring的IOC注解开发入门
1.1.1创建Web项目引入Jar包
在Spring4的版本中,除了引入基本的开发包以外,还需要引入aop的包。
1.1.2引入Spring的配置文件
在src下创建applicationContext.xml,使用注解开发需要引入context的约束。
<?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/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">
</beans>
1.1.3创建接口和实现类
接口:
package com.albertyy.spring.demo1;
/**
* 用户管理DAO层接口
* @author yxy
*
*/
public interface UserDAO {
public void save();
}
实现类:
package com.albertyy.spring.demo1;
/**
* 用户管理DAO层实现类
* @author yxy
*
*/
public class UserDAOImpl implements UserDAO {
@Override
public void save() {
System.out.println("UserDAOImpl执行了...");
}
}
1.1.4开启Spring的组件扫描
<!-- Spring的IOC的注解入门 -->
<!-- 使用IOC注解开发,配置组件扫描(那些包下的类使用IOC注解) -->
<context:component-scan base-package="com.albertyy.spring.demo1"></context:component-scan>
1.1.5在类上添加注解
package com.albertyy.spring.demo1;
import org.springframework.stereotype.Component;
/**
* 用户管理DAO层实现类
* @author yxy
*
*/
@Component("userDao") //相当于<bean name="userDAO" class="com.albertyy.spring.demo1.UserDAOImpl" />
public class UserDAOImpl implements UserDAO {
@Override
public void save() {
System.out.println("UserDAOImpl执行了...");
}
}
1.1.6编写测试类
@Test
/**
* Spring的IOC注解方式
*/
public void demo2(){
// 创建Spring的工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDAO userDAO = (UserDAO) applicationContext.getBean("userDao");
userDAO.save();
}
1.1.7注解方式设置属性的值
使用注解方式设置值可以没有set方法。如果属性有set方法,需要将属性注入的注解添加到set方法上,如果属性没有set方法,将属性注入的注解添加到属性上。
/**
* 用户管理DAO层实现类
* @author yxy
*
*/
@Component("userDao") //相当于<bean name="userDAO" class="com.albertyy.spring.demo1.UserDAOImpl" />
public class UserDAOImpl implements UserDAO {
@Value("李四")
private String name;
// @Value("张三")
// public void setName(String name) {
// this.name = name;
// }
@Override
public void 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")
public class UserServiceImpl implements UserService {
//注入Dao
// @Autowired
// @Qualifier("userDao")
@Resource(name="userDao")
private UserDao userDao;
@Override
public void 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和注解开发的比较
适用场景:
- xml: 可以适用任何场景 。
- 好处:结构清晰,后期方便维护
- 注解:有些地方用不了,比如:这个类,不是自己提供的 。
- 好处:开发方便
1.2.5 XML和注解混合使用
- XML管理Bean,注解完成属性注入。
<!-- 在没有扫描的情况下,使用属性注入的注解:@Resource,@Value,@Autowired,@Qualifier -->
<context:annotation-config></context:annotation-config>
2.Spring的AOP的XML开发
2.1什么是Aop
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。原有项目功能上,通过aop去添加新的功能,这些功能是建立在原有的功能基础上的,而且不会修改原来代码以及逻辑。
打个不恰当的比方,这就好像我们吃汉堡,想要加个牛排,直接把牛排加在里面就行了,而不会影响原来汉堡里面的东西,利用Aop思想编程也是同样的道理,我们想要在程序中新加一个功能,就像在汉堡中加上一个牛排,不会影响原来的程序。
2.2Spring底层的Aop实现原理
- 动态代理
- JDK动态代理:只能对实现了接口的类产生代理
- 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的约束
<?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">
</beans>
2.5.3编写目标类并完成配置
目标类:
package com.albertyy.demo1;
public class ProductDaoImpl implements ProductDao {
@Override
public void save() {
System.out.println("保存");
}
@Override
public void update() {
System.out.println("修改");
}
@Override
public void delete() {
System.out.println("删除");
}
@Override
public void find() {
System.out.println("查找");
}
}
配置:
<!-- 配置目标对象,即被增强的对象 -->
<bean id="productDao" class="com.albertyy.demo1.ProductDaoImpl"></bean>
2.5.4编写测试类
- Spring整合Junit单元测试
引入Spring-test的jar包
代码编写:
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")
public class Demo1 {
@Resource(name="productDao")
private ProductDao pd;
@Test
public void 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
*
*/
public class MyAspectXML {
public void checkPri(){
System.out.println("-------权限校验------");
}
}
- 配置切面:将切面类交给Spring管理
<!-- 将切面类交给Spring管理 -->
<bean id="myAspect" class="com.albertyy.demo1.MyAspectXML"></bean>
2.5.6通过AOP配置实对目标类产生代理
<!-- 通过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)然后打印就可以获得切入点的信息。
public class MyAspectXML {
/*
* 前置通知
*/
public void 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为名字的参数 打印即可获得切入点的返回值。
/*
* 后置通知
*/
public void 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("-----环绕前通知-------");
Object b= joinPoint.proceed();
System.out.println("-----环绕后通知-------");
return b;
}
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3" />
2.6.4异常抛出通知:在程序抛出异常的时候进行操作
/*
* 异常抛出通知
*/
public void afterThrowing(Throwable ex){
System.out.println("-----异常抛出通知-------"+ex.getMessage());
}
<!-- 异常抛出通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
2.6.5最终通知:无论是否有异常,都执行(相当于try-catch中的finally)
//最终通知:相当于finally
public void after(){
System.out.println("-----最终通知");
}
<!-- 最终通知 -->
<aop:after method="after" pointcut-ref="pointcut4" />
2.6.6引介通知(略)
2.7Spring切入点的表达式语法
- 基于execution的函数完成的
- 语法:
- [访问修饰符] 方法返回值 包名.类名.方法名(参数) 。
- public void com.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 复制这段内容后打开百度网盘手机App,操作更方便哦