1.什么是spring?
Spring是一个分层的一站式轻量级开源框架
2.spring的使用
如果要使用spring中的东西,就必须被spring管理
2.1Spring的jar包下载与导入
Spring的官网:spring.io,下载对应的压缩文件。
2.2项目的环境搭建
1.下载好之后,打开lib,里面是所有的jar包,把RELEASE.jar结尾的包导入到新建的java项目lib中。
2.编写配置文件applicationContext.xml的约束
在项目下新建一个config的文件夹,让它变成资源目录。新建一个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:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" 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>
3.新建一个测试目录,用于做测试
2.3.IOC快速入门
IOC:inversion of Controller(控制反转),把对象的控制权交给spring。原来由我们自己实例化的对象交给spring容器来实始化,这时对象的实始化的权利就会反转。
使用spring打印HelloSpring案例:
创建一个hello的类,在里面写一个方法:
package com.test; public class Hello { public void say(){ System.out.println("hello,goodmonring"); } }
修改配置文件applicationContext.xml,让其交给spring管理:
<!--bean将某个java对象交给spring管理,id是给bean取名,class指定要被管理的类的路径--> <bean id="hello" class="com.test.Hello"></bean>
测试:
@Test public void helloTest(){ //加载配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean对象 Hello hello = (Hello) context.getBean("hello"); //调用方法 hello.say(); }
2.4DI快速入门
DI:dependency injection 依赖注入。在spring框架负责创建Bean对象时,动态将依赖对象注入到Bean组件中,简单的说就是给对象的属性注入值。
使用spring给User的属性赋值案例
1.通过属性注入值
第一步:创建user对象,添加get和set方法
package com.entity; public class User { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
第二步:把user交给spring管理并通过属性注入值
<bean id="user" class="com.entity.User"> <!--通过属性注入值,必须提供get和set方法--> <property name="name" value="元慧"></property> <property name="age" value="23"></property> </bean>
第三步:测试
@Test public void test2(){ //加载配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean对象 User user = (User) context.getBean("user"); //调用方法 System.out.println(user.toString()); }
2.通过构造方法注入值
第一步:给User对象添加有参构造
第二步:把user交给spring管理并通过构造方法注入值
<bean id="user" class="com.entity.User"> <!--构造注入内容,必须提供有参构造--> <constructor-arg name="name" value="123"></constructor-arg> <constructor-arg name="age" value="20"></constructor-arg> </bean>
第三步:测试
3.通过标签p/c注入
通过c标签注入
<!--通过标签c注入值,必须提供有参构造,c指构造--> <bean id="user" class="com.entity.User" c:name="王五" c:age="20"></bean>
通过p标签注入
<!--通过标签p注入值,必须提供无参构造和set方法,p指属性--> <bean id="user" class="com.entity.User" p:name="王五" p:age="20"></bean>
面试题:IOC和DI区别?
IOC 控制反转,是指对象实例化权利由spring容器来管理
DI 依赖注入,在spring创建对象的过程中,对象所依赖的属性通过配置注入对象中。
3.bean属性注入
3.1.ref的使用
在一个实体类中持有另一个实体类的引用,就可以用到ref属性。
car类
package com.entity; @Getter @Setter @ToString public class Car { private String brand; private double price; private User user; }
注入值
<bean id="user" class="com.entity.User"> <!--通过属性注入值,必须提供get和set方法--> <property name="name" value="元慧"></property> <property name="age" value="23"></property> </bean> <bean id="car" class="com.entity.Car"> <property name="brand" value="迈巴赫"></property> <property name="price" value="8000000"></property> <property name="user" ref="user"></property> </bean>
测试
@Test public void test3(){ //加载配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取bean对象 Car car = (Car) context.getBean("car"); //调用方法 System.out.println(car); }
3.2集合属性的注入
简单类型的类
package com.entity; import java.util.List; import java.util.Map; import java.util.Set; @Getter @Setter @ToString public class Coll { private List<String> list; private Set<String> set; private Map<String,String> map; }
复杂类型的注入
package com.entity; import java.util.List; import java.util.Map; import java.util.Set; @Getter @Setter @ToString public class Coll { private List<User> list; private Set<User> set; private Map<String, List<User>> map; }
1. list属性注入
简单类型的注入
<bean id="coll" class="com.entity.Coll"> <property name="list"> <list> <value>张三</value> <value>李四</value> <value>王五</value> <value>张三</value> </list> </property> </bean>
测试
@Test public void test5(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Coll coll = (Coll) context.getBean("coll"); System.out.println(coll); }
复杂类型的注入
<bean id="user" class="com.entity.User"> <!--通过属性注入值,必须提供get和set方法--> <property name="name" value="元慧"></property> <property name="age" value="23"></property> </bean> <bean id="user2" class="com.entity.User"> <property name="name" value="郭慧"></property> <property name="age" value="20"></property> </bean> <bean id="coll" class="com.entity.Coll"> <property name="list"> <list> <ref bean="user"></ref> <ref bean="user2"></ref> </list> </property> </bean>
测试结果
1. Set属性注入
简单类型的注入
复杂类型的注入:同list的复杂类型注入,这里只需要把list改为set即可
1. Map输入注入
简单类型的注入
<bean id="coll" class="com.entity.Coll"> <property name="map"> <map> <entry key="name" value="张三"></entry> <entry key="sex" value="女"></entry> <entry key="age" value="20"></entry> </map> </property> </bean>
复杂类型的注入
<bean id="user" class="com.entity.User"> <!--通过属性注入值,必须提供get和set方法--> <property name="name" value="元慧"></property> <property name="age" value="23"></property> </bean> <bean id="user2" class="com.entity.User"> <property name="name" value="郭慧"></property> <property name="age" value="20"></property> </bean> <bean id="coll" class="com.entity.Coll"> <property name="map"> <map> <entry key="计算机1班" value-ref="user"></entry> <entry key="计算机2班" value-ref="user2"></entry> </map> </property> </bean>
4. spring注解开发
在spring中使用注解必须进行包扫描,还有开启注解。
在applicationContext.xml文件中引入:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
然后在下面开启注解,进行包扫描
<!--开启注解--> <context:annotation-config></context:annotation-config> <!--注解包扫描--> <context:component-scan base-package="com.test"></context:component-scan>
4.1@Component
在类的前面加上这个注解,就可以把它交给spring管理,不需要在xml中配置,相当于xml中配置一个<bean>标签。
常用方式:在后面加个括号,括号里面给这个类起个名字
package com.test; import org.springframework.stereotype.Component; //把student交给spring管理,并起名为student,方便spring来查找 @Component("student") public class Student { public void student(){ System.out.println("111111"); } }
测试同上,在此略。
4.2@Value()和 @Autowired
@Value是给简单的属性注入值, @Autowired给复杂属性注入值。
给words注入值
public class Student { @Value("学生") private String words; public void student(){ System.out.println(words); } }
给复杂属性注入值,Autowired是按照类型注入的:
@Autowired
private User user;
通过注入之后,如果给User的属性已经注入了值,那么这里的user里面就有值了
4.3 @Autowired的扩展
@Autowired @Qualifier("user") private User user;
根据名字给复杂属性注入值,这样的好处是可以解决一个类有多个子类而找不到具体哪一个类的问题。而这两个注解有可以合为一个:
@Resource(name="user")
4.4@Component的优化
在spring2.5后为@Component添加了三个衍生的注解
@Repository 用于DAO层
@Service 用于service层
@Controller 用于表现层
4.5登录案例
Dao层
package com.dao.impl; import com.dao.UserDao; import com.entity.User; import org.springframework.stereotype.Repository; @Repository public class UserDaoImpl implements UserDao { @Override public void login(User user) { if("zys".equals(user.getName())&&"20".equals(user.getAge())){ System.out.println("登录成功"); }else{ System.out.println("登录失败"); } } }
package com.dao.impl; import com.dao.UserDao; import com.entity.User; import org.springframework.stereotype.Repository; @Repository public class UserDaoImpl implements UserDao { @Override public void login(User user) { if("zys".equals(user.getName())&&"20".equals(user.getAge())){ System.out.println("登录成功"); }else{ System.out.println("登录失败"); } } }
Service层
package com.service.impl; import com.dao.UserDao; import com.entity.User; import com.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Autowired UserDao dao; @Override public void login(User user) { dao.login(user); } }
接口
package com.service; import com.entity.User; public interface UserService { void login(User user); }
Controller层
package com.controller; import com.entity.User; import com.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class UserController { @Autowired UserService service; public void login(User user){ service.login(user); } }
测试类
package com.test; import com.controller.UserController; import com.entity.User; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; public class LoginTest { @Autowired UserController controller; @Test public void login(){ User user=new User(); user.setAge(20); user.setName("zys"); controller.login(user); } }
运行会出现如下错误:
出现这个错误是因为测试类和Spring没有整合,如果想要在测试类中整合Spring需要将Spring和junit整合起来。整合步骤如下:
1、导入整合相关jar
2、在测试类上配置如下内容完成整合
/使用spring的测试环境 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml")
配置完成之后就可以测试了。
5.SpringAOP
5.1aop概述
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。主要用来记录日志
AOP与OOP区别
OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。换而言之,OOD/OOP面向名词领域,AOP面向动词领域。
5.2aop入门
1.导入相关的jar包
2.在applicationContext.xml中配置
引入命名空间:
xmlns:aop="http://www.springframework.org/schema/aop"
引入约束:
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
3.编写测试相关的类(xml方式)
3.1编写目标类UserDao:
package com.controller; public class UserDao { public void add(){ System.out.println("操作数据库啦"); } }
3.2编写增强类UserHelper,这个类用于在add方法调用之前执行:
package com.controller; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class UserHelper implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println("我是增强类的before方法"); } }
3.3修改applicationContext.xml:
<!--交给spring管理--> <bean class="com.controller.UserDao" id="userDao"></bean> <bean class="com.controller.UserHelper" id="userHelper"></bean> <!--aop配置--> <aop:config> <!--配置切点 expression="execution(* com.controller.UserDao.add(..))" 切点表达式,*表示返回值类型,..表示任意参数--> <aop:pointcut id="addPoint" expression="execution(* com.controller.UserDao.add(..))"/> <!--当调用add方法时通知hepler--> <aop:advisor advice-ref="userHelper" pointcut-ref="addPoint"></aop:advisor> </aop:config>
3.4测试:
package com.test; import com.controller.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; //使用spring的测试环境 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class LoginTest { @Autowired UserDao dao; @Test public void test(){ dao.add(); } }
输出结果:
我是增强类的before方法
操作数据库啦
3.5整合aspect
1)自定义增强类:
package com.controller; public class Helper { public void before(){ System.out.println("before方法"); } public void after(){ System.out.println("after方法"); } }
2)修改applicationContext.xml:
<!--交给spring管理--> <bean class="com.controller.UserDao" id="userDao"></bean> <bean class="com.controller.Helper" id="helper"></bean> <!--aop配置--> <aop:config> <aop:aspect ref="helper"> <aop:pointcut id="addCut" expression="execution(* com.controller.UserDao.add(..))"/> <aop:before method="before" pointcut-ref="addCut"></aop:before> <aop:after method="after" pointcut-ref="addCut"></aop:after> </aop:aspect> </aop:config>
3)测试:测试输出的结果是 before方法,操作数据库啦,after方法
4.编写相关的测试类(注解方式)
4.1.修改applicationContext.xml:
<!--配置aop代理--> <aop:aspectj-autoproxy/> <!--开启注解扫描--> <context:component-scan base-package="com" />
4.2编写目标类:
package com.controller; import org.springframework.stereotype.Repository; @Repository public class UserDao { public void add(){ System.out.println("操作数据库啦"); } }
4.2编写增强类:
package com.controller; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class Helper { @Before(value = "execution(* com.controller.UserDao.add(..))") public void before(){ System.out.println("before方法"); } @After(value = "execution(* com.controller.UserDao.add(..))") public void after(){ System.out.println("after方法"); } }
4.4测试,测试结果同上。
4.5其他通知类型
1)后置通知
//后置通知 @AfterReturning(value = "execution(* com.controller.UserDao.add(..))",returning = "value") public void afterReturn(JoinPoint jp,Object value){ System.out.println("后置通知的返回值是"+value); }
2)环绕通知
//环绕通知 @Around(value = "execution(* com.controller.UserDao.add(..))") public Object around(ProceedingJoinPoint jp) throws Throwable { Object o = jp.proceed(); return o; }
2)异常通知(常用):
//import org.apache.log4j.Logger;导这个包 Logger logger=Logger.getLogger(Helper.class); //异常通知 @AfterThrowing(value = "execution(* com.controller.UserDao.add(..))",throwing = "e") public void afterThrow(Throwable e){ //把错误信息表保存到日志中 logger.error(e); }
5.aop代理
aop原理:动态代理
JDK代理:Jdk动态代理只针对于接口操作
CGLIb:为没有实现接口的类去做代理,也可以为接口做代理
代理:对原有类中的方法进行增强
包装:会在原有方法的基础之上增加一些方法
6.Scope注解
@Scope它以描述bean的作用域(单例或多例)。
Singleton:单例模式,内存中只会有一个该对象,是默认的模式。
Prototype:多例模式,每次使用都初始化一个新的对象。一般用在controller或service层,增加访问带宽
@Repository @Scope("Prototype") //指定为多例模式 public class UserDao { ... }