在pom.xml里添加
xxxxxxxxxx
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.4</version>
</dependency>
在maven的dependencise里会出现
xxxxxxxxxx
package com.yang.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class People {
private Cat cat;
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
xxxxxxxxxx
package com.yang.pojo;
public class Cat {
public void shout(){
System.out.println("喵~");
}
}
xxxxxxxxxx
package com.yang.pojo;
public class Dog {
public void shout(){
System.out.println("旺~");
}
}
@Autowired可以自动装配,就无需set方法,需要在变量上面写上@Autowired
也不用再用beans.xml里进行一个一个的引用,但是需要在头部添加xml 完整的xml如下:
xxxxxxxxxx
<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:annotation-config/>
<!--指定扫描包下的注解,这个包下的注解就会生效-->
<context:component-scan base-package="com.yang"/>
<bean id="cat" class="com.yang.pojo.Cat"/>
<bean id="dog" class="com.yang.pojo.Dog"/>
<!--autowire="byName"根据名称进行自动装配,需要满足所有的id唯一-->
<!--autowire="byType"根据类型进行自动装配,需要满足所有的class唯一-->
<!--有了自动装配就不用再写这个关联了-->
<!--<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>-->
<bean id="people" class="com.yang.pojo.People"/>
</beans>
创建MyTest.java
xxxxxxxxxx
import com.yang.pojo.People;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people",People.class);
people.getDog().shout();
people.getCat().shout();
}
}
需要在pom.xml里添加依赖
在需要运行的Java方法上面写上@Test可以简便的运行当前方法,从而不运行整个程序,如上面的MyTest.java中的test1()
xxxxxxxxxx
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
使用@Nullable注解,说明这个字段可以为null值
例如:在有参构造器的参数前加上@Nullable,此时可以使name的值为null值
xxxxxxxxxx
public People( String name) {
this. name = name ;
}
使用@Qualifier注解,@Autowired和@Qualifier为一套需要搭配使用,如果beans.xml中有两个相同的对象例如
xxxxxxxxxx
<bean id="cat222" class="com.yang.pojo.Cat"/>
<bean id="cat2" class="com.yang.pojo.Cat"/>
如上有两个Cat对象分别为cat222和cat2此时People类会报错,这个时候可以在People实体类中添加@Qualifier注解配合@Autowired注解指定唯一的bean对象,这样就不会报错了,但是需要类型一样。
xxxxxxxxxx
value = "cat2") (
private Cat cat;
如果不想使用@Autowired和@Qualifier可以使用Java自带注解@Resource
使用@Resource需要在pom.xml里添加annotation依赖
xxxxxxxxxx
<dependencies>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
在成员变量上加上@Resource
xxxxxxxxxx
private Cat cat;
private Dog dog;
@Resource会先比较是否有相同的id,如果id都不一样,那么会比较class最后的类型例如com.yang.pojo.Cat
会寻找是否为pojo后面的Cat类型
xxxxxxxxxx
<bean id="cat" class="com.yang.pojo.Cat"/>
<bean id="dog" class="com.yang.pojo.Dog"/>
当有两个id不同但相同类型的bean时,可以给@Resource添加name属性
xxxxxxxxxx
<bean id="cat1" class="com.yang.pojo.Cat"/>
<bean id="cat2" class="com.yang.pojo.Cat"/>
<bean id="dog" class="com.yang.pojo.Dog"/>
xxxxxxxxxx
name = "cat2") (
private Cat cat;
private Dog dog;
注意:自动装配 现在基本都用@Autowired搭配@Qualifier基本不用@Resource
@Autowired :自动装配先通过类型查找,再通过名字查找 如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")进行bean id的指定 @Nullable字段标记了这个注解,说明这个字段可以为null; @Resource: 自动装配先通过名字查找,再通过类型查找
*使用注解一定要导入AOP的包,如果导入了spring的核心springframework默认包含了AOP的依赖包,其次增加beans.xml里的context约束
使用@Component注解进行开发,@Component就相当于图中第3处的作用
上图中4处的值也可以使用@Value进行赋值
xxxxxxxxxx
package com.yang.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
public class User {
public String name;
//@Value("小杨")相当于bean里的值
"小杨") (
public void setName(String name) {
this.name = name;
}
}
@Value("小杨")可以放在public String name;上面,如果提供set方法也可以放在set方法上面进行赋值。
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!,以下的@Repository @Service @Controller与@Component功能都是等价的,只不过分层不同,都是代表将某个类注册到Spring中,装配Bean dao 层使用 @Repository service层使用 @Service controller层使用 @Controller
因此@Component注解处的图第2处扫描改成com.yang这样dao service controller pojo就都能被扫描到了
xxxxxxxxxx
"singleton") (
public class User {
public String name;
//@Value("小杨")相当于bean里的值
"小杨") (
public void setName(String name) {
this.name = name;
}
}
@Scope注解有两个常用属性
singleton:单例模式,只会创建一个bean对象
prototype:原型模式,会创建多个bean对象
使用@Configuration可以完全摒弃xml配置文件使用纯Java的配置方式,这种方式在springboot中随处可见,例子如下
User.java实体类
xxxxxxxxxx
package com.yang.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//@Component说明User类被Spring接管了,注册到了容器中
public class User {
private String name;
public String getName() {
return name;
}
"小杨") //给name赋值 (
public void setName(String name) {
this.name = name;
}
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
config.java配置文件
xxxxxxxxxx
package com.yang.config;
import com.yang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//这个也会Spring容器托管,注册到容器中,因为他本米就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看的beans
//扫描包
"com.yang") (
Config2.class)//将第二个配置类导入,相当于xml里的导入多个xml文件 (
public class Config {
//注册一个bean,就相当于之前在xml里写的bean标签
//这个方法名字就相当于bean标签里的id
//这个方法的返回值就相当于bean标签的class属性
public User getUser(){
return new User();//就是返回要注入bean的对象
}
}
config2.java配置文件
xxxxxxxxxx
package com.yang.config;
import org.springframework.context.annotation.Configuration;
public class Config2 {
}
MyTest.java测试类文件
xxxxxxxxxx
import com.yang.config.Config;
import com.yang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}
参考图:
角色分析:
代理模式的好处:
代理模式的缺点:
例如租房 Rent(租房接口) Proxy(代理/中介) Host(房东/出租房屋的人) Client(顾客/租房的人)
步骤:
接口
xxxxxxxxxx
package com.yang.demo01;
//租房
public interface Rent {
public void rent();
}
真实角色
xxxxxxxxxx
package com.yang.demo01;
//房东
public class Host implements Rent{
public void rent() {
System.out.println("房东要出租房子");
}
}
代理角色
xxxxxxxxxx
package com.yang.demo01;
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
//中介替房东租房
public void rent() {
seeHouse();
host.rent();
hetong();
cost();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//收中介费
public void cost(){
System.out.println("中介收中介费");
}
//签合同
public void hetong(){
System.out.println("中介签租赁合同");
}
}
客户端访问代理角色
xxxxxxxxxx
package com.yang.demo01;
//租房的人
public class Client {
public static void main(String[] args) {
//房东要租房子
Host host = new Host();
//代理,中介帮房东租房子,但是呢?代理角色一般会有一些附属操作!
Proxy proxy = new Proxy(host);
//你不会面对房东,直接找中介租房即可!
proxy.rent();
}
}
租房系统图如下:
AOP面向切面编程,即程序纵向运行,增加功能但不改变原有代码,改为横向运行,即为AOP的实现机制,以下为一个例子:
例如使用代理模式在不改变原有代码的基础上增加日志输出功能
原有代码:
UserService接口
xxxxxxxxxx
package com.yang.demo02;
//抽象对象
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
UserServiceImpl.java实现类
xxxxxxxxxx
package com.yang.demo02;
//真实对象
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
Client.java测试类
xxxxxxxxxx
package com.yang.demo02;
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
userService.add();
}
}
输出结果增加了一个用户
如果想要不改变原有代码在每次输出时加上”使用了xxx方法“,那么需要创建一个代理类,同样实现UserService的接口
修改后代码:
UserServiceProxy.java
xxxxxxxxxx
package com.yang.demo02;
public class UserServiceProxy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
//打印日志方法
public void log(String msg){
System.out.println("使用了"+ msg +"方法");
}
}
修改Client.java
xxxxxxxxxx
package com.yang.demo02;
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
//创建代理对象
UserServiceProxy userServiceProxy = new UserServiceProxy();
//使用set方法传入代理对象
userServiceProxy.setUserService(userService);
//使用对象方法
userServiceProxy.add();
}
}
解决静态代理每增加一个真实角色就会产生一个代理角色的缺点
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的!
动态代理分为两大类 : 基于接口的动态代理,基于类的动态代理
动态代理万能模板
ProxyInvocationHandler.java
xxxxxxxxxx
package com.yang.demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//等我们会用这个类,自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制实现
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String msg){
System.out.println("执行了"+ msg +"方法");
}
}
UserService接口
xxxxxxxxxx
package com.yang.demo04;
//抽象对象
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
UserServiceImpl.java
xxxxxxxxxx
package com.yang.demo04;
//真实对象
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
Client.java
xxxxxxxxxx
package com.yang.demo04;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色,现在不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);
UserService proxy = (UserService) pih.getProxy();
proxy.delete();
}
}
需要在pom.xml中导入依赖包
xxxxxxxxxx
<!--使用AOP-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一:使用Spring的API接口,以添加日志为例子
applicationContext.xml
xxxxxxxxxx
<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:annotation-config/>
<!--指定扫描包下的注解,这个包下的注解就会生效-->
<context:component-scan base-package="com.yang"/>
<!--给每个类注册bean-->
<bean id="userService" class="com.yang.service.UserServiceImpl"/>
<bean id="log" class="com.yang.log.Log"/>
<bean id="afterLog" class="com.yang.log.AfterLog"/>
<!--方式一 使用原生的API接口-->
<!--配置AOP 上方导入AOP的约束-->
<aop:config>
<!--首先需要一个切入点 expression为表达式,有固定格式execution(要执行的位置)-->
<aop:pointcut id="pointcut" expression="execution(* com.yang.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<!--使log类切入到pointcut上-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
UserService接口 service文件夹
xxxxxxxxxx
package com.yang.service;
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
UserServiceImpl.java service文件夹
xxxxxxxxxx
package com.yang.service;
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void select() {
System.out.println("查询了一个用户");
}
}
Log.java log文件夹 MethodBeforeAdvice在程序执行之前添加日志
xxxxxxxxxx
package com.yang.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//method 要执行的目标对象的方法
//args 参数
//target 目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
}
}
AfterLog.java log文件夹,AfterReturningAdvice为在程序最后添加日志
xxxxxxxxxx
package com.yang.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + method.getName() + "方法,返回结果为:" + returnValue);
}
}
方式二:自定义类实现AOP
上述实例去掉Log文件夹及内文件
修改applicationContext.xml
xxxxxxxxxx
<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:annotation-config/>
<!--指定扫描包下的注解,这个包下的注解就会生效-->
<context:component-scan base-package="com.yang"/>
<!--给每个类注册bean-->
<bean id="userService" class="com.yang.service.UserServiceImpl"/>
<bean id="log" class="com.yang.log.Log"/>
<bean id="afterLog" class="com.yang.log.AfterLog"/>
<!--方式二-->
<bean id="diy" class="com.yang.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面 ref要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.yang.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
创建diy文件夹并创建
DiyPointCut.java
xxxxxxxxxx
package com.yang.diy;
public class DiyPointCut {
public void before(){
System.out.println("=====方法执行前=====");
}
public void after(){
System.out.println("=====方法执行后=====");
}
}
其余文件不动,即可实现第二种自定义类实现AOP
方式三:使用Spring注解实现AOP
applicationContext.xml 导入aop的约束
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
xxxxxxxxxx
<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:annotation-config/>
<!--指定扫描包下的注解,这个包下的注解就会生效-->
<context:component-scan base-package="com.yang"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
</beans>
UserService.java接口
xxxxxxxxxx
package com.yang.service;
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
UserServiceImpl.java实现类
xxxxxxxxxx
package com.yang.service;
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void select() {
System.out.println("查询了一个用户");
}
}
AnnotationPointCut.java切面类 注意:导包要导aspectj下面的
标注这个类是一个切面
方法执行前
方法执行后
环绕方法
xxxxxxxxxx
package com.yang.pojo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
public class AnnotationPointCut {
"execution(* com.yang.service.UserServiceImpl.*(..))") (
public void before(){
System.out.println("=====方法执行前=====");
}
"execution(* com.yang.service.UserServiceImpl.*(..))") (
public void after(){
System.out.println("=====方法执行后=====");
}
"execution(* com.yang.service.UserServiceImpl.*(..))") (
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
//调用执行方法
Object proceed = jp.proceed();
System.out.println("环绕后");
}
}
MyTest.java
xxxxxxxxxx
import com.yang.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userServiceImpl");
userService.add();
}
}
程序执行结果:
环绕前 =====方法执行前===== 增加了一个用户 =====方法执行后===== 环绕后
mybatis-config.xml
xxxxxxxxxx
<configuration>
<!--别名-->
<typeAliases>
<package name="com.yang.pojo"/>
</typeAliases>
<environments default="development">
<!--开发环境-->
<environment id="development">
<!--事务管理-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="yws1147632750"/>
</dataSource>
</environment>
</environments>
</configuration>