目录
1、Spring概念
2、Ioc容器
1、什么是Ioc
2、底层原理
入门案例
4、Spring提供Ioc容器实现的两种方式(两个接口)
5、ApplicationContext接口的常用实现类
6、什么是Bean管理
7、Bean管理的两种方式
3、Aop
1、什么是Aop?
?2、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
3、AOP一些专业术语
?4、AOP操作(准备)
?5、AOP操作(AspectJ注解方式)
??6、AOP操作(AspectJ配置文件方式)
?课程链接:尚硅谷-Spring5框架最新版教程(idea版)_哔哩哔哩_bilibili
Spring官网:Spring | Home
jar下载地址(我是找的maven仓库,哪里下载都可以):https://mvnrepository.com/
Spring是轻量级的开源的J2EE框架
Spring解决企业级应用开发的复杂性
Spring有两个核心部分:Ioc(控制反转:将创建对象的过程交给Spring来管理)、Aop(面向切面编程:在不改变源码的基础上对功能进行增强)
Spring特点:
? ? ? ? (1)、方便解耦、简化开发
? ? ? ? (2)、AOP编程的支持
? ? ? ? (3)、方便程序的测试
? ? ? ? (4)、方便和其他框架整合
? ? ? ? (5)、方便进行事务的操作
? ? ? ? (6)、降低API的开发难度
2、Ioc容器
1、什么是Ioc
(1)控制反转就是把创建对象和对象之间的调用交给Spring进行管理
(2)使用Ioc目的:为了降低耦合度
2、底层原理
? ? ? ? xml解析、工厂模式、反射
主要用到的jar包:????????
????????????????????????????????spring-beans-5.2.6.RELEASE.jar
????????????????????????????????spring-context-5.2.6.RELEASE.jar
????????????????????????????????spring-core-5.2.6.RELEASE.jar
????????????????????????????????spring-expression-5.2.6.RELEASE
????????????????????????????????commons-logging-1.2.jar(Spring不含此包,需要单独下载)
入门案例
利用配置文件创建对象、注入属性
User.java
package com.atguigu.spring5;
/**
* 创建对象演示类
*/
public class User {
public void add(){
System.out.println("add.....");
}
}
Book.java
package com.atguigu.spring5;
public class Book {
private String bname;
private String bauthor;
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}public void print(){
System.out.println(bname+bauthor);
}
}
Orders.java
package com.atguigu.spring5;
/**
* 利用构造方法注入属性演示类
*/
public class Orders {
private String oname;
private String address;
public Orders(String oname,String address){
this.oname=oname;
this.address=address;
}
public void print() {
System.out.println(oname+address);
}
}
配置文件bean1.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置User对象创建 -->
<bean id="user" class="com.atguigu.spring5.User"></bean>
<bean id="book" class="com.atguigu.spring5.Book">
<!-- 使用property完成属性注入(set方法) -->
<property name="bname" value="易筋经"></property>
<property name="bauthor" value="达摩"></property>
</bean>
<bean id="orders" class="com.atguigu.spring5.Orders">
<!-- 使用constructor-arg完成属性注入(构造方法) -->
<constructor-arg name="oname" value="电脑"/>
<constructor-arg name="address" value="中国"/>
</bean>
</beans>
测试类TestSpring5.java
package com.atguigu.spring5.testdemo;
import com.atguigu.spring5.Book;
import com.atguigu.spring5.Orders;
import com.atguigu.spring5.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring5 {
@Test
public void testAdd(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
User user =context.getBean("user", User.class);
System.out.println(user);
user.add();
}
@Test
public void testBook(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
Book book=context.getBean("book",Book.class);
System.out.println(book);
book.print();
}
@Test
public void testOrders(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
Orders orders=context.getBean("orders",Orders.class);
System.out.println(orders);
orders.print();
}
}
控制台打印
com.atguigu.spring5.User@a74868d
add.....
com.atguigu.spring5.Book@2eda0940
易筋经达摩
com.atguigu.spring5.Orders@4c762604
电脑中国
Process finished with exit code 0
4、Spring提供Ioc容器实现的两种方式(两个接口)
?(1)、BeanFactory*:Ioc容器基本实现,是Spring内部使用接口,一般不提供给开发人员使用。在加载配置文件的时候不会创建对象,在获取对象(使用)时才会去创建对象。
?(2)、ApplicationContext:是BeanFactory的子接口,提供更多更强大的功能,一般有开发人员使用。在加载配置文件的时候就会创建配置文件中配置的对象。
*在实际项目中一般把耗时耗资源的操作在项目启动时处理所以用ApplicationContext更合适。
5、ApplicationContext接口的常用实现类
(1)FileSystemXmlApplicationContext
(2)ClassPathXmlApplicationContext
6、什么是Bean管理
主要指两个操作
(1)、Spring创建对象
(2)、Spring注入属性
7、Bean管理的两种方式
(1)、基于xml配置文件方式实现
????????使用<bean>标签创建对象
<!-- 配置User对象创建 -->
<bean id="user" class="com.atguigu.spring5.User"></bean>
? ? ? 在创建对象的基础上使用<property>标签注入属性
<bean id="book" class="com.atguigu.spring5.Book">
<!-- 使用property完成属性注入(set方法) -->
<property name="bname" value="易筋经"></property>
<property name="bauthor" value="达摩"></property>
</bean>
? ?向属性中设置空值
<bean id="book" class="com.atguigu.spring5.Book">
<!-- 使用property完成属性注入(set方法) -->
<property name="bname" value="易筋经"></property>
<property name="bauthor">
<!--向属性中设置空值-->
<null/>
</property>
</bean>
?向属性中设置特殊符号
<bean id="book" class="com.atguigu.spring5.Book">
<!-- 使用property完成属性注入(set方法) -->
<!-- 设置特殊符号 -->
<!-- 使用转义字符输入<<>> -->
<property name="bname" value="<<易筋经>>"></property>
<!-- 把带有特殊符号的内容写到CDATA -->
<property name="bauthor">
<value><![CDATA[<<达摩>>]]></value>
</property>
</bean>
?????使用<constructor-arg>标签注入属性
<bean id="orders" class="com.atguigu.spring5.Orders">
<!-- 使用constructor-arg完成属性注入(构造方法) -->
<constructor-arg name="oname" value="电脑"/>
<constructor-arg name="address" value="中国"/>
</bean>
使用<property>标签ref属性注入属性对象(外部注入)
<bean id="userService" class="com.atguigu.spring5.service.UserService">
<!--注入属性对象-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<!--创建要注入的对象-->
<bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
注入属性对象(内部注入)
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<property name="dept">
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="保安部"></property>
</bean>
</property>
</bean>
级联赋值(两种写法)
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dept.dname" value="保安部"></property>
</bean>
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<property name="dept" ref="dept">
<!--注入dept的属性,属性需要有get方法-->
<property name="dept.dname" value="保安部"></property>
</property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept"></bean>
注入集合属性
<bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
<!--注入数组属性-->
<property name="courses">
<array>
<value>java课程</value>
<value>数据库课程</value>
</array>
</property>
<property name="list">
<list>
<value>张三</value>
<value>法外狂徒</value>
</list>
</property>
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
<property name="courseList">
<!--对象类型的集合-->
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean class="com.atguigu.spring5.collectiontype.Course" id="course1">
<property name="cname" value="Spring5框架"></property>
</bean>
<bean class="com.atguigu.spring5.collectiontype.Course" id="course2">
<property name="cname" value="MyBatis"></property>
</bean>
引入util名称空间,把集合注入部分提取出来
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="bookList">
<value>易筋经</value>
<value>九阳神功</value>
<value>大悲咒</value>
</util:list>
<bean class="com.atguigu.spring5.collectiontype.Book" id="book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
</beans>
工厂bean(FactoryBean)
package com.atguigu.spring5.factorybean;
import com.atguigu.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;
public class MyBean implements FactoryBean<Course> {
@Override
public Course getObject() throws Exception {
Course course=new Course();
course.setCname("aaa");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
package com.atguigu.spring5.collectiontype;
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.atguigu.spring5.factorybean.MyBean" id="myBean">
</bean>
</beans>
测试工厂bean的方法
@Test
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
控制台输出结果
Course{cname='aaa'}
Process finished with exit code 0
利用bean标签scope属性设置bean是单实例对象还是多实例对象,Spring中默认是单实例对象
*(单实例每次创建都是引用同一个对象,多实例每次创建都是一个新的对象)
测试方法(多次获取对象输出,比较对象是否相同)
@Test
public void testCollection2() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1);
System.out.println(book2);
}
单实例配置?
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="bookList">
<value>易筋经</value>
<value>九阳神功</value>
<value>大悲咒</value>
</util:list>
<!--默认和scope="singleton"为单实例-->
<bean class="com.atguigu.spring5.collectiontype.Book" id="book" scope="singleton">
<property name="list" ref="bookList"></property>
</bean>
</beans>
?输出的两次对象相同
com.atguigu.spring5.collectiontype.Book@10d59286
com.atguigu.spring5.collectiontype.Book@10d59286
Process finished with exit code 0
多实例配置?
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="bookList">
<value>易筋经</value>
<value>九阳神功</value>
<value>大悲咒</value>
</util:list>
<!--多实例-->
<bean class="com.atguigu.spring5.collectiontype.Book" id="book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
</beans>
输出的两次对象不同?
com.atguigu.spring5.collectiontype.Book@10d59286
com.atguigu.spring5.collectiontype.Book@fe18270
Process finished with exit code 0
Bean生命周期演示?
package com.atguigu.spring5.bean;
public class Orders {
private String oname;
public Orders() {
System.out.println("第一步:创建bean实例");
}
public void setOname(String oname) {
System.out.println("第二步:调用set方法赋值");
this.oname = oname;
}
public void initMethod(){
//需要在配置文件中配置
System.out.println("第三步:调用初始化方法");
}
private void destroyMethod() {
//需要在配置文件中配置,手动调用才会执行
System.out.println("第五步:调用销毁方法");
}
}
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--init-method配置初始化方法,destroy-method配置销毁方法-->
<bean class="com.atguigu.spring5.bean.Orders" id="orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
</beans>
@Test
public void testBean() {
// ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步:获取到创建出来的bean对象" + orders);
//手动调用销毁方法
context.close();
}
?控制台输出
第一步:创建bean实例
第二步:调用set方法赋值
第三步:调用初始化方法
第四步:获取到创建出来的bean对象com.atguigu.spring5.bean.Orders@569cfc36
第五步:调用销毁方法
Process finished with exit code 0
?添加后置处理器后的生命周期
package com.atguigu.spring5.bean;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public java.lang.Object postProcessBeforeInitialization(java.lang.Object bean, java.lang.String beanName) throws org.springframework.beans.BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
@Override
public java.lang.Object postProcessAfterInitialization(java.lang.Object bean, java.lang.String beanName) throws org.springframework.beans.BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.atguigu.spring5.bean.Orders" id="orders" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
<!--配置后置处理器-->
<bean class="com.atguigu.spring5.bean.MyBeanPost" id="myBeanPost"></bean>
</beans>
第一步:创建bean实例
第二步:调用set方法赋值
在初始化之前执行的方法
第三步:调用初始化方法
在初始化之后执行的方法
第四步:获取到创建出来的bean对象com.atguigu.spring5.bean.Orders@569cfc36
第五步:调用销毁方法
Process finished with exit code 0
?自动装配(自动为属性赋值:根据名称/根据类型)
通过设置Bean标签中autowire属性
根据属性名称自动装配
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.atguigu.spring5.autowire.Emp" id="emp" autowire="byName">
<!-- <property name="dept" ref="dept"></property>-->
</bean>
<bean class="com.atguigu.spring5.autowire.Dept" id="dept"></bean>
</beans>
根据属性类型自动装配?
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.atguigu.spring5.autowire.Emp" id="emp" autowire="byType">
<!-- <property name="dept" ref="dept"></property>-->
</bean>
<bean class="com.atguigu.spring5.autowire.Dept" id="dept"></bean>
</beans>
?引入外部文件
直接配置
<?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">
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
</beans>
?引入外部.properties文件
<?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">
<!--需要引入context名称空间-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
</beans>
jdbc.properties?
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=123456
?(2)、基于注解方式实现
注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值..)
注解可以作用在类、方法、属性上面
使用注解的目的:简化xml配置,
创建对象的注解:
- @Component 业务特殊组件层,如handler类
- @Controller 业务控制层
- @Service 业务逻辑层
- @Repository 业务资源层
*这四个注解功能是一样的,都可以用来创建Bean实例
?基于注解方式创建对象
需要先引入aop依赖:spring-aop-5.2.6.RELEASE.jar
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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启组件扫描 -->
<!-- base-package属性多个包可以用“,”隔开。相同目录下多个包,写上层目录 -->
<context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
<!--use-default-filters="false"表示现在不使用默认的filter,自己配置filter,context:include-filter:设置扫描哪些内容-->
<!--<context:component-scan base-package="com.atguigu.spring5" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>-->
<!--context:exclude-filter:设置哪些内容不扫描-->
<!--<context:component-scan base-package="com.atguigu.spring5">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>-->
</beans>
?注解方式开启组件扫描
package com.atguigu.spring5.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
}
?自动装配类UserService
package com.atguigu.spring5.Service;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
//注解里value值可以省略,默认是首字母小写的类名,例如UserService类默认为userService
//@Component(value = "userService")
@Service
public class UserService {
public void add(){
System.out.println("service add..........");
}
}
测试方法?
package com.atguigu.spring5.testdemo;
import com.atguigu.spring5.Service.UserService;
import com.atguigu.spring5.config.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring5Demo1 {
//基于xml配置文件开启扫描器的测试方法
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
//基于注解开启扫描器的测试方法
@Test
public void test2() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
}
两次输出结果相同?
com.atguigu.spring5.Service.UserService@2f7c2f4f
service add..........
Process finished with exit code 0
?基于注解方式注入属性
????????@AutoWired:根据属性类型进行注入
????????@Qualifer:根据属性名称进行注入
????????@Resource:可以根据类型注入,也可以根据名称注入(不属于Spring,属于Javax)
????????@Value:普通类型属性注入
package com.atguigu.spring5.dao;
public interface UserDao {
public void add();
}
package com.atguigu.spring5.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void add(){
System.out.println("Dao add.........");
}
}
?根据类型注入
package com.atguigu.spring5.Service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
//@Component(value = "userService")
@Service
public class UserService {
//不需要set方法
//根据属性注入
@Autowired
private UserDao userDao;
public void add(){
System.out.println("service add..........");
userDao.add();
}
}
com.atguigu.spring5.Service.UserService@123ef382
service add..........
Dao add.........
Process finished with exit code 0
?根据名称注入
package com.atguigu.spring5.dao;
import org.springframework.stereotype.Repository;
@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{
@Override
public void add(){
System.out.println("Dao add.........");
}
}
package com.atguigu.spring5.Service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
//@Component(value = "userService")
@Service
public class UserService {
@Autowired
//当有多个实现类时就需要按名称注入,搭配@Autowired
@Qualifier(value = "userDaoImpl1")
private UserDao userDao;
public void add(){
System.out.println("service add..........");
userDao.add();
}
}
??@Resource:可以根据类型注入,也可以根据名称注入
package com.atguigu.spring5.Service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
//@Component(value = "userService")
@Service
public class UserService {
//@Resource根据类型注入
@Resource
private UserDao userDao;
public void add(){
System.out.println("service add..........");
userDao.add();
}
}
package com.atguigu.spring5.Service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
//@Component(value = "userService")
@Service
public class UserService {
//@Resource根据名称注入
@Resource(name = "userDoImpl1")
private UserDao userDao;
public void add(){
System.out.println("service add..........");
userDao.add();
}
}
?@Value普通类型注入
package com.atguigu.spring5.Service;
import com.atguigu.spring5.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
//@Component(value = "userService")
@Service
public class UserService {
@Autowired
//当有多个实现类时就需要按名称注入,搭配@Autowired
@Qualifier(value = "userDaoImpl1")
// //@Resource根据类型注入
// @Resource
// //@Resource根据名称注入
// @Resource(name = "userDoImpl1")
private UserDao userDao;
//注入普通类型
@Value(value = "abc")
private String name;
public void add(){
System.out.println("service add.........."+name);
userDao.add();
}
}
com.atguigu.spring5.Service.UserService@bef2d72
service add..........abc
Dao add.........
Process finished with exit code 0
3、Aop
1、什么是Aop?
(1)、面向切面(方面)编程,利用Aop可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)、通俗来说:就是不通过修改源码的方式,往主干功能里增加新功能。
(3)、底层原理:
? ? ? ? Aop底层使用动态代理
? ? ? ? ? ? ? ? 第一种,有接口情况,使用JDK动态代理
创建接口实现类代理方法,增强类的方法
? ? ? ? ? ? ? ? 第二种,没有接口情况,使用CGLIB动态代理
创建子类的代理对象,增强类方法
?2、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
(1)、调用newProxyInstance方法
?方法有三个参数:
????????ClassLoader?loader:类加载器
? ? ? ??类<?>[]?interfaces:增强方法所在的类,这个类实现的接口,支持多个接口
?????????InvocationHandler?h:实现这个接口InvocationHandler,创建代理对象,写增强的方法。
有接口的情况具体代码
package com.atguigu.spring5;
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
package com.atguigu.spring5;
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
package com.atguigu.spring5;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces={UserDao.class};
//可以直接写一个匿名类,也可以先写一个类UserDaoProxy实现InvocationHandler接口
// Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return null;
// }
// });
UserDaoImpl userDao=new UserDaoImpl();
UserDao dao=(UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,new UserDaoProxy(userDao));
int result=dao.add(1,2);
System.out.println("result:"+result);
}
}
class UserDaoProxy implements InvocationHandler{
private Object object;
public UserDaoProxy(Object object){
this.object=object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----------方法之前执行-----------"+method.getName()+":传递的参数"+ Arrays.toString(args));
Object res=method.invoke(object,args);
System.out.println("-----------方法之后执行-----------"+object);
return res;
}
}
<?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">
<!-- 开启组件扫描 -->
<context:component-scan base-package="com.atguigu.spring5"></context:component-scan>
</beans>
3、AOP一些专业术语
(1)、连接点:AOP类里面哪些方法可以被增强,哪些方法就是连接点
(2)、切入点:实际被增强的方法,称为切入点
(3)、通知(增强):实际增强的逻辑部分,称为通知
? ? ? ? ? ? ? ? 通知有多种类型:
? ? ? ? ? ? ? ? ? ? ? ? @Before? ? ? ? ? ? ? ? ?前置通知:方法之前执行
? ? ? ? ? ? ? ? ? ? ? ? @AfterReturning????后置通知:方法之后执行
? ? ? ? ? ? ? ? ? ? ? ? @Around????????????????环绕通知:方法之前之后都执行
? ? ? ? ? ? ? ? ? ? ? ? @AfterThrowing? ? ?异常通知:方法出现异常时执行
? ? ? ? ? ? ? ? ? ? ? ? @After? ? ? ? ? ? ? ? ? ? 最终通知:方法之后一定会执行
(4)、切面:把通知应用到切入点的过程,叫做切面
?4、AOP操作(准备)
? ? ? ? 1、Spring框架一般都是基于AspectJ*实现AOP操作
??????????????? *AspectJ不是Spring的组成部分,是独立的AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作
? ? ? ? 2、基于AspectJ实现AOP操作
? ? ? ? ? ? ? ? (1)、基于XML配置文件方式
? ? ? ? ? ? ? ? (2)、基于注解方式(常用)?
? ? ? ? 3、引入依赖
? ? ? ? ? ? ? ? ?Spring中:??
? ? ? ? ? ? ? ? ?单独:
? ? ? ? ? ? ? ? ?全部:
? ? ? ? ?4、切入点表达式
? ? ? ? ? ? ? ? (1)、作用:知道对哪个类里面的哪个方法进行增强
? ? ? ? ? ? ? ? (2)、写法:execution([权限修饰符*][返回类型][类全路径][方法名称]([参数列表**]))
? ? ? ? ? ? ? ? ? ? ? ? *用“*”号表示任意权限修饰符
????????????????????????**用“..”表示方法中的参数
? ? ? ? ? ? ? ? ? ? ? ? 例1:对com.atguigu.dao.BookDao类里面的add方法进行增强
?????????????????????????execution(*?com.atguigu.dao.BookDao.add(..))
? ? ? ? ? ? ? ? ? ? ? ? 例2:对com.atguigu.dao.BookDao类里面的所有方法进行增强
?????????????????????????execution(*?com.atguigu.dao.BookDao.*(..))
? ? ? ? ? ? ? ? ? ? ? ? 例3:对com.atguigu.dao包里面所有类的方法进行增强
?????????????????????????execution(*?com.atguigu.dao.*.*(..))
?5、AOP操作(AspectJ注解方式)
?被增强的类User
package com.atguigu.spring5.aopanno;
import org.springframework.stereotype.Component;
//被增强的类
@Component
public class User {
public void add(){
System.out.println("add.....");
}
}
?增强类UserProxy
package com.atguigu.spring5.aopanno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
//增强类
@Component
@Aspect//生成代理对象
@Order(2)//设置优先级,越小优先级越高
public class UserProxy {
//相同切入点抽取
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointdeom(){
}
//前置通知
@Before(value = "pointdeom()")
public void before(){
System.out.println("before.....");
}
//后置通知
@AfterReturning(value = "pointdeom()")
public void afterReturning(){
System.out.println("afterReturning.....");
}
//最终通知
@After(value = "pointdeom()")
public void after(){
System.out.println("after.....");
}
//异常通知
@AfterThrowing(value = "pointdeom()")
public void afterThrowing(){
System.out.println("afterThrowing.....");
}
//环绕通知
@Around(value = "pointdeom()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前.....");
proceedingJoinPoint.proceed();
System.out.println("环绕之后.....");
}
}
?增强类PersonProxy
package com.atguigu.spring5.aopanno;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect//生成代理对象
@Order(3)//设置优先级,越小优先级越高
public class PersonProxy {
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add())")
public void before(){
System.out.println("PersonProxy before");
}
}
配置文件?
<?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.atguigu.spring5.aopanno"></context:component-scan>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
?测试类
package com.atguigu.spring5.test;
import com.atguigu.spring5.aopanno.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void testAopAnno(){
ApplicationContext context= new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
控制台
环绕之前.....
before.....
PersonProxy before
add.....
环绕之后.....
after.....
afterReturning.....
进程已结束,退出代码为 0
??6、AOP操作(AspectJ配置文件方式)
被增强的类Book
package com.atguigu.spring5.aopxml;
public class Book {
public void buy(){
System.out.println("buy......");
}
}
增强类BookProxy?
package com.atguigu.spring5.aopxml;
public class BookProxy {
public void Before(){
System.out.println("Book before");
}
}
?配置文件
<?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">
<!--创建对象-->
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
<!--aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体方法上-->
<aop:before method="Before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
</beans>
测试类?
package com.atguigu.spring5.test;
import com.atguigu.spring5.aopxml.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void testAopXml(){
ApplicationContext context= new ClassPathXmlApplicationContext("bean2.xml");
Book book = context.getBean("book", Book.class);
book.buy();
}
}
|