一、spring的简介
spring理念:是现有的技术更加容易使用,本身是一个大杂烩。
SSH:Struct2 + Spring + Hibernate
SSM: SpringMVC + Spring + Mybatis
-
spring是开源的免费的容器。
-
spring是一个轻量级的,非入侵式的。
-
支持事务处理,对框架整合的支持。
-
控制反转(IOC),面向切面编程 (AOP)。
总结:spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
二、spring的使用
第一步:需要导入jar(Maven依赖)。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
第二步:创建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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
三、spring ioc
概述:描述spring的ioc,简单来说就是帮我们创建bean(对象),让我们不用再创建对象。
3.1、bean创建
(1)使用无参构造创建bean
<bean id="address" class="com.kuang.pojo.Address"></bean>
-
id:是这个bean的唯一标注
-
class: 是类的权限定类名
(2)使用有参构造创建bean
<!--第一种方法:通过下标赋值创建-->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg index="0" value="HollwWord"></constructor-arg>
</bean>
<!--第二种:通过类型创建,不建议使用-->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg type="java.lang.String" value="HolleWord"></constructor-arg>
</bean>
<!--第三种:通过参数名来创建-->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg name="name" value="琴江"></constructor-arg>
</bean>
3.2、bean作用域
<!--
id : bean 的唯一标识符 使用getBean获取对象的参数
class : bean对象的权限定名:包名+类型
name : 也是别名,而且name可以取多个别名
-->
<bean id="user" class="com.kuang.pojo.User" name="newUser" scope="singleton">
<constructor-arg name="name" value="琴江"></constructor-arg>
</bean>
<alias name="user" alias="newUser2"></alias>
<!--
bean的作用域
由bean的scope属性的值决定,默认是单例模式singleton
值 说明
singleton 单例模式
prototype 原型模式
单例模型:容器中只有一份实例,供所有人使用
原型模式:每次从容器中get的时候,都会产生一个新对象
-->
3.3、bean的注入
-
bean的注入本质就是通过set方法进行注入,所有一定要有set方法否则会报错
第一种:普通值注入,value
<property name="name" value="张三"></property>
第二种:bean注入,ref
<bean id="address" class="com.kuang.pojo.Address">
<property name="address" value="广东省茂名市信宜市"></property>
</bean>
<bean id="student" class="com.kuang.pojo.Student">
<property name="address" ref="address"></property>
</bean>
第三种:数组注入
<bean id="student" class="com.kuang.pojo.Student">
<property name="books">
<array>
<value>《鬼谷子》</value>
<value>《狂神说》</value>
</array>
</property>
</bean>
第四种:List<T>集合注入
<property name="hobbys">
<list value-type="java.lang.String">
<value>打篮球</value>
<value>打游戏</value>
<value>看电视</value>
</list>
</property>
第五种:Map<T,V>集合注入
<property name="card">
<map >
<entry key="身份证" value="486513486518756515"></entry>
<entry key="学生证" value="0983109486"></entry>
</map>
</property>
第六种:set<T>集合注入
<set>
<value>LOL</value>
<value>CF</value>
</set>
第七种:null值注入
<property name="wife">
<null/>
</property>
第八种: Properties值注入
<property name="info">
<props>
<prop key="学号">0983109486</prop>
<prop key="性别">男</prop>
</props>
</property>
3.4、bean的自动装配
(1)
通过bean标签的 autowire属性来设置。
-
byName :会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean(id 不区分大小写)
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="杨龙江"/>
</bean>
-
byType :会自动在容器上下文中查找,和自己对象属性相同的bean
<bean id="people1" class="com.kuang.pojo.People" autowire="byType">
<property name="name" value="杨龙江"/>
</bean>
(2)
通过注解来实现bean的自动装配
<!--
使用注解进行装配要注意
1、要先加入约束
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"
2、开启注解支持
<context:annotation-config/>
@Autowired
直接在属性上使用即可!也可以在set方式上使用!
使用@Autowired我们可以不用编写set方法,前提是你这个自动装配的属性在IOC(spring)容器中存在,且符合
名字byName!
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以
使用@Qualifier(value="xxx")
@Resource这是一个java原生的注解,也可以实现自动装配
-->
public class People {
@Autowired
private Dog dog;
@Autowired
private Cat cat;
private String name;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3.4、使用注解方式来创建bean
(1)功能:将该这个bean注册到spring的IOC容器中,等价于<bean id="user" class="com.kuang.pojo.User"></bean>(下面四个注解功能都一样)
-
@Controller 用在controller层
-
@Service 用在service层
-
@ Repository 用在mapper层
-
@Component 用在pojo层
(2)功能:设置这个bean的作用域
-
@Scope("xxxx") prototype 原型模式 singleton 单例模式(默认)
(3)功能:给bean注入值 用法:放在属性上面,或者放在set方法上也可以
-
@Value("xxxx")
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描指定包下的注解,这个包下的注解就会生效-->
<context:component-scan base-package="com.kuang"/>
<!--开启注解配置-->
<context:annotation-config/>
</beans>
//@Component 等价于 <bean id="user" class="com.kuang.pojo.User"></bean>
//也就是直接在IOC容器中注册了User的bean
@Component
@Scope("prototype")
public class User {
@Value("狂神")
public String name="张三";
}
四、使用java的方式来配置spring
完全不使用xml文件。
准备一个cat的类。
@Component
public class Cat {
@Value("cat")
private String name;
@Value("13")
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 "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
然后创建一个spring的配置类。
//标志这个类被spring托管,这是一个配置类
@Configuration
//扫描该包下的注解
@ComponentScan("com.kuang.pojo")
//合并KuangConfig和KuangConfig2这两个配置类
@Import(KuangConfig2.class)
public class KuangConfig {
//将这个类注册到spring容器中
@Bean
public User getUser(){
return new User();
}
@Bean
public Cat getCat(){
return new Cat();
}
}
测试
public class MyTest {
@Test
public void test1(){
//如果完全使用java代码,脱离xml文件,需要用AnnotationConfigApplicationContext来读取配置类
ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
User user = (User)context.getBean("getUser");
System.out.println(user.toString());
Cat cat = (Cat)context.getBean("getCat");
System.out.println(cat.toString());
}
}
五、动态代理
1、准备一个接口
public interface Rent {
//出租房子
public void rent();
}
2、实现这个接口
public class Host implements Rent {
public void rent() {
System.out.println("房东要出租房子了!");
}
}
3、创建一个类实现 InvoationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//调用该类自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//处理代理实例得到返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//动态代理的本质,就是使用反射机制实现
Object result = method.invoke(rent,args);
fare();
return null;
}
public void seeHouse(){
System.out.println("中介带看房子");
}
public void fare(){
System.out.println("收中介费");
}
}
4、测试
public class Clicnt {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象!
pih.setRent(host);
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
六、spring的AOP
使用aop需要到入aop的约束
public interface UserService {
public String add();
public void updata();
public void delete();
public void query();
}
public class UserServiceImpl implements UserService{
public String add() {
return "新增数据成功";
}
public void updata() {
System.out.println("修改一条数据");
}
public void delete() {
System.out.println("删除一条数据");
}
public void query() {
System.out.println("查询一条数据");
}
}
(1)使用原生的spring api接口
public class AfterLog implements AfterReturningAdvice {
//AfterReturningAdvice 后置通知,代码执行后执行
//returnValue 返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"返回结果为:"+returnValue);
}
}
public class Log implements MethodBeforeAdvice {
//MethodBeforeAdvice 前置通知,执行之前执行
//method 要执行的目标对象的方法
//args 参数
//target 目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
<aop:config>
<!--切入点:expression-->
<aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
(2)自定义类
public class DiyPointCut {
public void before(){
System.out.println("========方法执行前========");
}
public void after(){
System.out.println("========方法执行后========");
}
}
<bean id="diy" class="com.kuang.diy.DiyPointCut"></bean>
<aop:config>
<!--自定义切面,ref 要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
(3)通过注解实现AOP
需要导入aspectjrt包要不@Aspect会报红
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect//标记这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.kuang.service.*.*(..))")
public void Before(){
System.out.println("=======前置通知=========");
}
@After("execution(* com.kuang.service.*.*(..))")
public void after(){
System.out.println("=======后置通知=========");
}
//在环绕增强中,我们可以给定一个参数,代表我们要获取的切入点
@Around("execution(* com.kuang.service.*.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("=======环绕前======");
Signature signature = jp.getSignature();//获得签名
System.out.println("准备执行"+signature.getName()+"方法");
Object proceed = jp.proceed();//执行方法
System.out.println("=======环绕后======");
}
/*springAOP的执行顺序
* 1、执行这句代码 Object proceed = jp.proceed();前的方法
* 2、执行前置通知
* 3、执行方法
* 4、执行这句代码 Object proceed = jp.proceed();后的方法
* 5、执行后置通知
* */
}
<!--通过注解实现Aop-->
<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut"></bean>
<!--开启Aop注解支持 JDK(默认 proxy-target-class="false") cglib(proxy-target-class="true")-->
<aop:aspectj-autoproxy proxy-target-class="true"/>