SpringIOC和AOP
一、Spring核心技术
Spring核心技术:springIOC、DI、AOP还有事务管理、传播行为。
什么是Spring?
答:spring是一个容器,管理每个bean(对象)与bean(对象)之间的关系。
使用spring来管理。
在没有使用Spring的时候使用的三层架构。
这上面因为对象太多,不方便管理。所以才会使用Spring框架。
Spring好处:解耦、对象是单例的可以节约内存。
任何对象初始化的过程,全部交给Spring,用了Spring框架后,
就不能使用User user = new User();这种初始化方式了。
二、SpringIOC介绍
SpringIOC与DI(面试问)
什么是IOC?
答:IOC就是控制反转,将bean的对戏那个交给Spring容器进行管理。
IOC实现的原理是反射机制。
反射:创建对象。
什么是DI?
答:DI就是依赖注入。
解决对象之间的依赖关系,就比如userService依赖userDao。
三、SpringIOC依赖注入
项目如图所示:
第一步:创建UserEntity这个实体类
第二步:创建Spring.xml
第三步:在Spring.xml里面注入UserEntity这个实体类。如图
测试:当初手写SpringIOC也写过。这个对象就是通过Spring这个容器创建的
如果sporing.xml文件里,配置相同的bean id的时候会报错。如图。
第四、Spring创建对象的单例和多例作用域
Spring默认创建对象是单例的,可以去在spring.xml文件中修件。修改。
Spring的作用域。4种作用域。
单例:jvm只能创建一次,且只存在一个。
多例:每次运行都会创建一次。存在多个。
request:请求作用域在请求里才有效的。
session:对象和session绑定的,session什么时候失效,
对象就什么时候失效。
证明对象是单例的?直接去查看构造函数。执行一遍就是单例的。
使用单例模式注意事项:
答:饿汉式是天生线程安全的。因为饿汉是一开始就创建对象的。
饱汉式是线程不安全的。
spring使用的是饿汉式来创建对象。
将spring设置成多例的:
<bean id="userEntity1" class="com.leeue.entity.UserEntity"
scope="prototype">
</bean>
多例是不会产生线程安全的,因为多例每次都是新的对象。
第五、SpringIOC依赖注入
注入的方式有:
1、通过构造函数
2、通过set方法属性注入值
3、p名称空间
4、注解
SpringIOC创建对象默认走无参构造函数。
SpringIOC有参构造函数。
使用SpringIOC调用有参构造函数
对象:
spring.xml配置:
依赖DI 就是给对象做关联关系的
一、使用set方法做依赖注入:
案例:在service里注入dao。然后调用add方法。
DI:就是建立起依赖关系。
UserDao层:
UserService层:
spring.xml文件配置:
测试:
使用注解方式注入
如果包名不同,注入的id相同,默认使用第一个注入的。
配置包扫描:
报错:
@Autowired:默认是以类型来查找对象的
@Resource:是根据名称来查找对象的。 这个注解在jdk1.6之后才有,1.5是用不了的。
@Resource(name=”userDao02”)
@Autowired(required=false)@Qualifier("userDao02")
禁止类型查找,也通过名称来查找。
所以这里解决报错的方法就是加上标识符,使用@Resource来注入.
第六、SpringAOP
什么是代理设计模式?
答:作用:提供对目标对象进行访问的方式。(中介类似)
好处:提高安全性。
静态代理与动态代理的区别?
答:静态代理:需要生成代理类。需要自己创建对象
动态代理:不需要生成代理类。直接使用object
动态代理:
jdk动态代理:反射机制。
cglib动态代理:字节码。
什么是springAOP?
答:面向切面编程 --思想
应用场景:权限管理、事务管理、日志打印、性能监控。
什么地方项目才会使用aop?
答:重复代码。代码冗余。在不同的方法中,但是需要做相同的操作。
关注点:重复代码的地方。
切面:相当于把重复的代码抽取出来。
切入点:拦截哪些方法。
SpringAOP方式:注解方式、xml方式。
SpringAOP通知:
前置通知:
后置通知:
异常通知:
环绕通知:
运行通知:
切面编程使用方式:
第一步:在spring.xml开启aop事务权限
<!-- 开启aop事务注解,才能使用aop切面编程 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
第二步:定义切面
package com.leeue;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
*
* @classDesc: 功能描述:(切入点)
* @author:<a href="leeue@foxmail.com">李月</a>
* @Version:v1.0
* @createTime:2018年8月14日 下午4:43:43
*/
@Aspect//定义成切面,表示这个是个切面
@Component//表示把这个类注入到spring容器中。
public class Aop01 {
//Spring Aop通知?
/**
* 前置通知
*/
@Before(value = "execution(* com.leeue.service.UserService.add(..) )")
public void bean() {
System.out.println("前置通知......");
}
/**
*后置通知
*/
@After(value = "execution(* com.leeue.service.UserService.add(..) )")
public void commit() {
System.out.println("后置通知.....");
}
/**
* 运行通知
*/
@AfterReturning(value = "execution(* com.leeue.service.UserService.add(..) )")
public void afterRunning() {
System.out.println("运行通知.....");
}
/**
* 异常通知
*/
@AfterThrowing(value = "execution(* com.leeue.service.UserService.add(..) )")
public void afterThrowing() {
System.out.println("异常通知.....");
}
/**
* 环绕通知
* @throws Throwable
*/
@Around(value = "execution(* com.leeue.service.UserService.add(..) )")
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知......前");
point.proceed();//这个就是 执行 add 方法,如果没有就不执行 应用场景在权限,有权限就走
System.out.println("环绕通知......后");
}
}
使用xml方式来做切面编程
spring.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: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">
<bean id="userEntity1" class="com.leeue.entity.UserEntity"></bean>
<bean id="userEntity2" class="com.leeue.entity.UserEntity">
<constructor-arg name="userName" value="leeue"></constructor-arg>
<constructor-arg name="age" value="23"></constructor-arg>
</bean>
<bean id="userDao" class="com.leeue.dao.UserDao"></bean>
<bean id="userService" class="com.leeue.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 配置扫包 扫描包的范围 -->
<context:component-scan base-package="com.leeue"></context:component-scan>
<!-- 开启aop事务注解,才能使用aop切面编程 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 切面类 -->
<bean id="aop" class="com.leeue.Aop02"></bean>
<aop:config>
<!-- 定义一个切入点表达式: 拦截哪些方法 -->
<aop:pointcut expression="execution(* com.leeue.service.UserService.add(..) )" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pt"/>
<!-- 前置通知: 在目标方法调用前执行 -->
<aop:before method="begin" pointcut-ref="pt"/>
<!-- 后置通知: -->
<aop:after method="after" pointcut-ref="pt"/>
<!-- 运行通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
Aop02.java
package com.leeue;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
*
* @classDesc: 功能描述:(使用xml方式来实现切面编程)
* @author:<a href="leeue@foxmail.com">李月</a>
* @Version:v1.0
* @createTime:2018年8月14日 下午4:43:43
*/
public class Aop02 {
public void begin() {
System.out.println("前置通知......");
}
public void after() {
System.out.println("后置通知.....");
}
public void afterReturning() {
System.out.println("运行通知.....");
}
public void afterThrowing() {
System.out.println("异常通知.....");
}
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知......前");
point.proceed();//这个就是 执行 add 方法,如果没有就不执行 应用场景在权限,有权限就走
System.out.println("环绕通知......后");
}
}