IOC和AOP也需要个容器承载,spring相当这个容器,如果要用到这两个特性要在spring基础上去运行。
IOC
Spring通过控制反转(IOC)的技术促进了低耦合,一个对象依赖的其他对象会被通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。控制反转(Inversion of Control),是一种设计思想,一个重要的面向对象编程的法则,它能知道我们设计出松耦合的程序。传动应用程序都是由我们在类内主动创建依赖对象,从而导致类与类之间高耦合,难于测试,有了IOC容器之后,把创建和查找依赖对象的控制权,交个类容器,由容器进行注入组合对象,所以对象与对象之间就是松散耦合的,这样便于测试,功能复用,使整体程序体系结构变的灵活。DI(依赖注入)是实现Ioc的一种方法,控制反转是,获得依赖对象的方式反转了,其实Ioc对变成带来的最大改变不是从代码,是思想上,发生了“主从换位”的变化。应用程序原本是老大,要获得什么资源都是主动出击,但是Ioc/DI思想中,应用程序就变成被动的了,被动的等待Ioc容器来创建并注入所需要的资源了。
一、Bean的定义,<beans../>元素是spring配置文件的根元素,<beans.../>元素可以包含多个<bean..../>子元素。bean可以理解为实例化的对象,每一个Bean对应Spring容器里的一个Java实例,所以定义一个Bean需要有两个属性
Id,确定该Bean的唯一标识符,容器对Bean管理、访问、以及该Bean的依赖关系,都通过该属性完成,Bean的id属性在Spring容器中是唯一的。
Class,指定new的哪一个类,不能是接口类,spring会直接使用new关键字创建改Bean的实例,因此,这里必须提供Bean实现类的类名。例如,在配置一个Bean时,该Bean实现类中必须有个一个无参构造器,可以没有构造方法,如果有构造方法了,必须有一个无参数的构造方法
<bean id="bookDao" class="com.service.impl.BookDao"/>
容器的启动,暂时没用用tomcat容器,所以用spring自带的容器启动它,默认去resources
ApplicationContext context = new ClassPathXmlApplicationContext("IOCBeans01.xml");
通过xml注入的两种方式
一个是注解扫包
<bean id="bookDao" class="com.service.impl.BookDao"/>
<context:component-scan base-package="com.service.impl" />
把bookDao这个bean 赋值给@Autowired注解下面的那个成员变量
一个是xml配置
<bean id="bookService" class="com.service.impl.BookService">
<property name="iBookDao" ref="bookDao"></property>
</bean>
把bookDao这个bean,赋值给iBookDao这个成员变量
二、参数传递
constructor-arg 代表构造方法 和值
property name 代表set方法
<bean id="userDao" class="com.service.impl.UserDao">
<constructor-arg name="" value=""/>
<property name="" value=""/>
</bean>
三、Bean回调方法
回调方法,在初始化这个bean的时候,先执行一个方法
执行测试的时候,去启动容器,在启动容器过程中,就会出现new的这个操作,只针对这个bean自己初始化用
<bean id="userService" class="com.service.impl.UserService"
init-method="initMethod" destroy-method="destroyMethod">
<property name="iUserDao" ref="userDao"/>
</bean>
public void initMethod(){
System.out.println("初始化操作");
}
public void destroyMethod(){
System.out.println("关闭方法");
}
UserService userService = context.getBean("userService",UserService.class);
这个getBean里的是xml里配置的id,如果没有提供名字,就用spring默认的命名机制,即类名的第一个字母小写,强制类型转换,getBean拿到的是一个object类型,需要做类型转化,有两种方式,第一种在bean的名字后面加上UserService.class, 第二种在前面(UserService) context.getBean("userService")
四、使用Spring注解配置IOC
首先要在xml中配置扫描包,使用注解情况下要加这个扫描,
<context:component-scan base-package="com.service.impl" />
注解分为三类
@Repository用于DAO层的实现类进行注解
@Service用于业务层注解,功能和@Component
@Controller用于控制层注解,功能和@Component
五、初始化回调注解与销毁回调注解
@PostConstruct
public void initMethod(){
System.out.println("构造方法之后执行,初始化");
}
@PreDestroy
public void destroyMethod(){
System.out.println("销毁之前执行");
}
销毁是当bean被处理掉了之后,就会执行,跟执行什么方法没有关系
注解@PostConstruct等同于 xml里的 init-method="initMethod"
注解@PreDestroy 等同于xml里的destroy-method="destroyMethod"
六、自动装配/注入
使用注解@Autowired
七、零配置实现IOC
八、通过注解@Value获取properties配置
取properties里的值步骤
首先要有一个properties文件 ,类似一个map对象,key-value
然后新建一个包下面一个类,属性和properties里的一样 ,类用@Componet 组件的意思 扫描包, 添加get set toString 然后用spring初始化 注解@PostConstruct,输出,
然后新建一个xml ,用扫描包和位置的标签
component-scan base-package=
资源点位,资源的位置
property-placeholder location=“config/config.properties”
创建一个测试类
ApplicationContext applicationContext;
applicationContext = new ClassPathXmlApplicationContext(config.xml);
九、bean作用域
十、扫描过滤expression表达式
spring 注入bean的方式两种xml写法,一种是,相当对这个iBookDao成员变量赋值,把bookDao这个bean注入到bookService这个类里
<bean id="bookDao" class="com.service.impl.BookDao"/>
<bean id="bookService" class="com..service.impl.BookService">
<property name="iBookDao" ref="bookDao"></property>
</bean>
一种是注解方式,扫描包,在对应的类里的成员变量加上注解@Autowired,扫描到这个成员变量。@Autowired是按照类型注入的
<bean id="bookDao" class="com.service.impl.BookDao"/>
<context:component-scan base-package="com.service.impl" />
AOP
AOP(Aspect Oriented Programming)面向切面编程,什么地方应用,一般应用在日志。避免重复代码,较少对业务代码的入侵
AOP的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: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">
<context:component-scan base-package="com..service.impl"></context:component-scan>
<!--当有切面被触发的时候去执行这类里面的方法,有了切面之后需要一个类(bean)去承载执行-->
<bean id="halder" class="com.long.lesson.service.Halder"/>
<aop:config>
<!-- 切入点,在什么情况下去执行aop的内容-->
<aop:aspect id="time" ref="halder">
<!--切入点,在触发什么条件下进入切入点-->
<!--切入点表达式主要是触发条件,含义是Service类里面的所有方法,并且需要带参数才会切入-->
<!--id的值,和下面的pointcut-ref的值是一致的,说明before 和after执行的切点是id相同的那个
id和pointcut-ref 是一一对应的-->
<aop:pointcut id="addAllMethod"
expression="execution(* com.long.lesson.service.impl.*Service.*(*))"/>
<!--method的值是 切面类里的方法 -->
<!--before是在执行UserService里add方法之前,aop介入-->
<aop:before method="startTime" pointcut-ref="addAllMethod"/>
<!--after是在执行UserService里add方法之后,aop介入-->
<aop:after method="endTime" pointcut-ref="addAllMethod"/>
<!--环绕是在执行UserService里add方法之前之后,都介入aop-->
<aop:around method="aroundTest" pointcut-ref="addAllMethod"/>
</aop:aspect>
</aop:config>
</beans>
import org.aspectj.ProceedingJoinPoint;
import javax.xml.crypto.Data;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* Created by on 2018/12/22.
*/
//一把菜刀
public class Halder {
public void startTime(){
long startTime =System.currentTimeMillis();
System.out.println("开始执行时间:"+new Date());
}
public void endTime(){
long endTime =System.currentTimeMillis();
System.out.println("结束执行时间:"+new Date());
}
//环绕通知
public Object aroundTest(ProceedingJoinPoint proceedingJoinPoint){
//
// System.err.println("环绕通知进来的参数"+proceedingJoinPoint.getArgs());
// 拿目标类
// System.err.println(proceedingJoinPoint.getTarget());
// 拿目标方法
// System.err.println(proceedingJoinPoint.getSignature().getName());
Object arg = proceedingJoinPoint.getArgs()[0];
String s = (String)arg;
System.err.println("原来的环绕通知进来的参数:"+s);
Object[] args = proceedingJoinPoint.getArgs();
args[0]="你好我是环绕通知修改后的参数:";
try {
// System.err.println("我是调用:"+proceedingJoinPoint.getSignature().getName()+"之前的输出");
// 去执行目标方法的处理,执行proceed()之后去调用add方法
Object o = proceedingJoinPoint.proceed(args);
List list = (List)o;
list.clear();
list.add("哈哈哈,我是修改后的返回参数");
System.err.println(o);
// System.err.println("我是调用:"+proceedingJoinPoint.getSignature().getName()+"之后的输出");
return o;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}