Sping学习

一.IOC

1.什么是IOC

(1)控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理

(2)使用IOC的目的:为了降低耦合度

2.IOC底层实现原理

(1)xml解析、工程模式、反射

IOC底层原理

3.IOC接口

  • IO思想基于IOC容器完成,IOC容器底层就是对象工厂

  • Spring提供IOC容器实现两种方式:(两个接口)

(1)BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不提供给开发人员使用

-------------加载配置文件的时候不回去创建对象,在获取或使用对象的时候才去创建对象

(2)ApplicationContext:BeanFactory接口的子接口,提供了更多更强大的功能,一般有开发人员使用

-------------加载配置文件的时候就会把在配置文件中的对象进行创建

  • ApplicationContext接口有实现类:

image-20220523130452399

4.IOC操作Bean管理(基于xml方式)

  • 什么是Bean管理

1)Spring创建对象

2)Spring注入属性

  • Bean管理操作有两种方式

1)基于xml配置文件方式实现

2)基于注解方式实现

4.1 IOC操作Bean管理(基于xml方式)

1).基于xml方式创建对象

<bean id="user" class="com.yufou.Spring.User"></bean>

在Spring配置文件中,使用bean变迁,标签里面添加对应的属性,就可以实现对象创建

属性:

id属性:获取对象的唯一标识

class属性:类的全路径

创建对象时,默认执行无参构造方法

2).基于xml方式注入属性

DI:依赖注入,就是注入属性

------第一种注入方式:使用set方法注入、

(1)创建类,定义属性,创建set方法,使用无参构造

public class Orders {
   private String  oname;
   private String address;

   public String getOname() {
       return oname;
  }

   public void setOname(String oname) {
       this.oname = oname;
  }

   public String getAddress() {
       return address;
  }

   public void setAddress(String address) {
       this.address = address;
  }

   public Orders() {
  }

(2)设置Spring配置文件中的属性

<bean id="orders" class="com.yufou.pojo.Orders ">
   <property name="oname" value="abc"></property>
   <property name="address"    value="oname"></property>
</bean>

name:属性名

value:属性值

------第二种注入方式:使用有参构造注入

(1)创建类,定义属性,创建属性对应得有参构造方法

public class Orders {
   private String  oname;
   private String address;

   public Orders(String oname, String address) {
       this.oname = oname;
       this.address = address;
  }
}

(2)在Spring配置文件中进行配置

<bean id="orders" class="com.yufou.pojo.Orders">
   <constructor-arg name="oname" value="abc"></constructor-arg>
   <constructor-arg name="address" value="china"></constructor-arg>
</bean>

name:属性名

value:属性值

---------注入属性外部bean

(1)创建两个类service类和dao 类

(2)在service调用dao里面的方法

public class UserDaoImpl implements UserDao{
   @Override
   public void update() {
       System.out.println("dao update...............");
  }
}
----------------------------------------------------------------------------------
public interface UserDao {
   public void update();
}
----------------------------------------------------------------------------------
public class UserService {
   private UserDao userDao;

   public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
  }

   public void add() {
       System.out.println("service add...........");
       userDao.update();
  }
}

(3)在Spring配置文件中进行配置

<?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">
       <!--1.service和dao对象的创建-->
       <bean id="userService" class="com.yufou.service.UserService">
           <property name="userDao"    ref="userDao"></property>
       <!-- name属性:类里面的属性名称 -->
       <!-- ref属性:创建userDao对象bean标签的id值 -->
       </bean>

       <bean id="userDao" class="com.yufou.pojo.UserDaoImpl"></bean>

</beans>

 

 

--------- 注入属性内部bean和级联赋值

(1)一对多关系:部门和员工

一个部门有多个员工,一个员工属于一个部门

部门是一,员工是多

(2)在实体类之间表示一对多关系

public class Dept {
   //部门类
   private  String dname;

   public void setDname(String dname) {
       this.dname=dname;
  }
}
//员工表
public class Emp {
   private String ename;
   private  String gender;
   //一个员工属于一个部门
   private Dept dept;

   public void setEname(String ename) {
       this.ename = ename;
  }

   public void setDept(Dept dept) {
       this.dept = dept;
  }

   public void setGender(String gender) {
       this.gender = gender;
  }
}

(3)Spring配置文件

<!--内部bean-->
   <bean id="emp" class="com.yufou.pojo.Emp">
   <!--   设置两个普通的属性-->
       <property name="ename" value="lucy"></property>
       <property name="gender" value="女"></property>
   <!-- 对象类型的属性 -->
       <property name="dept">
           <bean id="dept" class="com.yufou.pojo.Dept">
               <property name="dname"  value="保安部"></property>
           </bean>
       </property>
   </bean>

4.2IOC操作Bean管理(FactoryBean)

1)Spring有两种类型bean,一种普通bean,另一种是工程bean(FactoryBean)

2)普通bean:在配置文件中定义bean类型就是返回类型

3)工厂bean:在配置文件定义bean类型可以喝犯规烈性不一样

4.3IOC操作Bean管理(bean作用域)

1)在Spring里面,默认情况下是单实例

2)如何设置是单实例还是多实例

(1)在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例

(2)scope的属性值

第一个值:默认值,singleton,表示是单实例对象

第二个值:prototype,表示多实例对象

(3)singleton和prototype区别

第一:singleton单实例;prototype多实例

第二:设置scope值是singleton时候,加载spring配置文件时候就会穿件单实例对象

设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,在调用getBean方法时候创建多实例对象

4.3IOC操作Bean管理(bean生命周期)

1)通过构造器创建bean的实例(无参数构造)

2)为bean的属性设置值和对其他bean的引用(调用set方法)

3)调用bean的初始化的方法(需要进行配置)

4)bean可以使用了(对象获取到了)

5)当容器关闭时,调用bean的销毁方法(需要进行配置)

5.IOC操作Bean管理(基于注解)

Spring针对Bean管理创建对象提供注解

(1)@Component

(2)@Service

(3)@Controller

(4)@Repository

*上面四个注解功能是一样的,都可以用来创建bean实例

5.1基于注解方式实现对象创建

1)开启扫描

开辟context上下文空间并设置扫描

<context:component-scan base-package="com.yufou"></context:component-scan>

2)创建类:

//在注解里面value属性值可以省略不写,默认值是类名称,首字母小写
@Component(value = "userService")//<bean id="userService" class="" ></bean>
public class UserService {
   public void add() {
       System.out.println("add userService.............");
  }
}

5.2基于注解方式实现属性注入

(1)@AutoWired 根据属性类型进行自动注入

1)把service和dao中创建实例的注解

2)在service注入dao对象,在service类添加dao类属性,在属性上面使用注解

//在注解里面value属性值可以省略不写,默认值是类名称,首字母小写
@Component(value = "userService")//<bean id="userService" class="" ></bean>
public class UserService {
   //定义dao属性
   //不需要添加set方法
   //添加注入属性注解
   @Autowired
   private UserDao userDao;
   public void add() {
       System.out.println("add userService.............");
  }
}

 

(2)@Qualifier 更加属性名进行注入

@Qualifier 要和@Autowired一起使用

//在注解里面value属性值可以省略不写,默认值是类名称,首字母小写
@Component(value = "userService")//<bean id="userService" class="" ></bean>
public class UserService {
   //定义dao属性
   //不需要添加set方法
   //添加注入属性注解
   @Autowired
   @Qualifier(value = "userDaoImpl1")//根据名称注入
   private UserDao userDao;
   public void add() {
       System.out.println("add userService.............");
       userDao.add();
  }
}

 

(3)@Resource 可以根据类型注入,也可以根据名称注入

    //@Resource//根据类型注入
   @Resource(name = "userDaoImpl1")//根据名称注入
   private UserDao userDao;
   public void add() {
       System.out.println("add userService.............");
       userDao.add();
  }
}

 

(4)@Value 注入普通类型属性

    @Value(value = "abc")
   private String name;

6.完全注解开发

1).创建配置类,替代xml配置文件

@Configuration //作为配置类,替代xml文件
@ComponentScan(basePackages = "com.yufou")//开启扫描
public class SpringConfig {
}

2)加载配置类

   ApplicationContext context=new  AnnotationConfigApplicationContext(SpringConfig.class);

二.AOP

1.什么是AOP

1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

AOP

2.AOP底层原理

1)AOP底层使用动态代理

(1)有个两种情况的的动态代理

  • 有接口的情况,使用JDK动态代理

    创建接口实现类代理对象,增强类的方法

  • 没有接口情况,使用CGLIB动态代理

    创建子类的代理对象,增强类的方法

3.AOP(JDK动态代理)

1)使用JDK动态代理,使用Proxy类

------>调用 newProxyInstance()方法

方法有三个参数

  • 类的加载器

  • 增强方法所在的类,这个类实现的接口,支持多个接口

  • 实现接口InvacationHandler,创建代理类对象,写增强的方法

2)编写JDK动态代理代码

------------>

创建接口,定义方法

public interface UserDao {
    int add(int a, int b);
   String   updaate(String id);
}

------------>

创建接口实现类,实现方法

public class UserDaoImpl implements UserDao{
   @Override
   public int add(int a, int b) {
       return a+b;
  }

   @Override
   public String updaate(String id) {
       return id;
  }
}

------------>

使用Proxy类创建接口代理对象

public class JDKProxy {
   public static void main(String[] args) {
       //创建接口实现类对象
       Class[] interfaces={UserDao.class};
       UserDaoImpl userDao = new UserDaoImpl();
       UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserdaoProxy(userDao));
       int res = dao.add(2, 3);
       System.out.println("res="+ res);
  }
}
class  UserdaoProxy implements InvocationHandler{
   //1.把创建的是谁的代理对象,把谁传递过来
   //有参构造进行传递
   private Object obj;
   public UserdaoProxy(Object obj) {
       this.obj=obj;
  }
//增强的逻辑
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       //方法之前
       System.out.println("方法之前执行........"+method.getName()+"传递的参数..."+ Arrays.toString(args));

       //被增强的方法执行
       Object res = method.invoke(obj, args);

       //方法之后
       System.out.println("方法之后执行"+obj);
       return res;
  }
}

4.AOP(术语)

1)连接点

2)切入点

3)通知(增强)

4)切面

5.AOP操作(准备工作)

1)Spring框架中一班基于AspectJ实现AOP操作

* 什么是AspectJ

------------->AspectJ不是Spring组成部分,是独立的AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

2)基于AspectJ实现AOP操作

  • 基于XML配置文件

  • 基于注解方式实现(使用)

3)在项目工程中引入AOP相关依赖

4)切入点表达式

------->切入点表达式作用:知道我们要对哪个类里面的哪个方法进行增强

------->语法结构:

execution(权限修饰符,返回类型,类全路径,方法名称,参数列表)

举例1:对com.yufou.dao.BookDao类粒粒面的add()进行增强

------->execution(* com.yufou.dao.BookDao.add(..))

举例2:对com.yufou.dao.BookDao类粒粒面的所有方法进行增强

------->execution(* com.yufou.dao.BookDao.*(..))

举例3:对com.yufou.dao包里面的所有类,类里面的所有方法进行增强

------->execution(* com.yufou.dao.*. ※(。。。))

6 AOP操作

AspectJ注解

------->创建类,在类里面定义方法

//被增强类
public class User {
   public void add() {
       System.out.println("add............");
  }
}

------->创建增强类(编写增强逻辑)

//增强类
public class UserProxy {
   public void before() {
       System.out.println("before............");
  }
}

------->进行通知的配置

1)在Spring配置文件中,开启注解扫描

<?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.aopanno"></context:component-scan>
</beans>

2)使用注解创建User 和UserPtoxy对象

 

3)在增强类上面添加注解@Aspect

//增强类
   @Component
   @Aspect//生成代理对象
public class UserProxy {
   public void before() {
       System.out.println("before............");
  }
}

 

4)在Sping配置文件中开启生成代理对象

<!--    开启AspectJ生成代理对象-->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

------->配置不同类型的通知

1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

//增强类
   @Component
   @Aspect//生成代理对象
public class UserProxy {
       //@Before注解表示作为前置通知
       @Before(value = "execution(* com.aopanno.User.add(..))")
   public void before() {
       System.out.println("before............");
  }
   @Around(value = "execution(* com.aopanno.User.add(..))")
   public void arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
       System.out.println("环绕之前...........");
       //被增强的方法执行
       proceedingJoinPoint.proceed();
       System.out.println("环绕之后..........");
  }
}

------->相同的切入点抽取

       //相同的切入点抽取
       @Pointcut(value = "execution(* com.aopanno.User.add(..))")
       public void point() {

      }
   @Around(value = "point()")
   public void arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
       System.out.println("环绕之前...........");
       //被增强的方法执行
       proceedingJoinPoint.proceed();
       System.out.println("环绕之后..........");
  }

------->有多个增强类对同一个方法增强,设置增强类的优先级

在增强类上面添加注解@Order(数字类型值),数字类型值越小,优先级越高

@Component
@Aspect
@Order(1)
public class PersonProxy {
   @Before(value = "execution(* com.aopanno.User.add(..))")
   public void before() {
       System.out.println("PersonBefore.................");
  }
}


posted @ 2022-05-23 21:02  与否业务NOW  阅读(25)  评论(0)    收藏  举报