Spring 是輕量級的開源的 JavaEE 框架,
Spring有兩個核心部分IOC 和 Aop
- IOC(Inversion of Control):控制反轉,把創建物件程序交給 Spring 進行管理
- Aop(Aspect Oriented Programming):面向切面編程,不修改源代碼進行功能增強
Spring特點:
- 方便解耦,簡化開發
- Aop 編程支持
- 方便程式測驗
- 方便和其他框架進行整合
- 方便進行事務操作
- 降低 API 開發難度
本篇介紹主要介紹AOP
底層原理
AOP的底層使用動態代理,動態代理有兩種情況,一種為有介面的情況(使用JDK動態代理),一種為沒有介面的情況(使用CGLIB動態代理)下面介紹的是有介面的情況
使用JDK動態代理:
關鍵方法newProxyInstance(ClassLoader loader, class<?>[] interfaces, InvocationHandler h)
該方法回傳指定介面的代理實體,loader:用戶定義代理類的類加載器;interfaces :要實作的代理類的介面串列;h:實作InvocationHandler的類,在重寫的invoke方法中加入自己增強的代碼部分,
使用Proxy類創建UserDao介面代理物件的代碼如下,UserDao為自己定義的一個介面,介面中有一個add方法,UserDaoImpl為介面實作類,
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDaoImpl = new UserDaoImpl();
//創建介面實作類代理物件
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoImpl));
//測驗
dao.add(1, 2);
}
}
//創建代理物件
class UserDaoProxy implements InvocationHandler{
private Object object;
//有參構造器傳遞物件
public UserDaoProxy(Object object){
this.object = object;
}
//寫增強的邏輯,在與其關聯的代理實體上呼叫方法時,invoke方法就會被呼叫
@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("原方法之后執行...");
return res;
}
}
運行結果如下:

自己的白話總結:創建InvocationHandler介面的實作類并重寫invoke方法,在invoke方法中添加自己的代碼增強部分,呼叫newProxyInstance回傳代理實體并向上轉型為介面,當我們呼叫介面中的方法時,就呼叫了invoke方法,從而實作了代碼的功能增強,如有錯誤請指正,
AOP操作實作
Spring 框架一般都是基于 AspectJ 實作 AOP 操作,AspectJ 不是 Spring 組成部分,它是獨立的 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,進行 AOP 操作,
基于 AspectJ 實作 AOP 操作有兩種方式:
- 基于xml組態檔實作
- 基于注解方式實作(常用)
相關術語與切入點運算式
-
連接點:可以被增強的方法
-
切入點:被增強的方法
-
通知:實際增強的邏輯部分(說人話:自己要添加的代碼)
通知的型別:
- 前置通知
- 后置通知
- 環繞通知
- 例外通知
- 最終通知
-
切面:把通知應用到切入點的程序(說人話:把增強的代碼應用到原方法中)
切入點運算式:
切入點運算式的作用:知道對哪個類里面的哪個方法進行增強
語法結構: execution([權限修飾符] [回傳型別] [類全路徑] [方法名稱]([引數串列]) )
相關示例如下:
舉例 1:對 com.hnust.spring5.dao.BookDao 類里面的 add 進行增強
execution(* com.hnust.spring5.dao.BookDao.add(..))
舉例 2:對 com.hnust.spring5.dao.BookDao 類里面的所有的方法進行增強
execution(* com.hnust.spring5.dao.BookDao.* (..))
舉例 3:對 com.hnust.spring5.dao 包里面所有類,類里面所有方法進行增強
execution(* com.hnust.spring5.dao.*.* (..))
基于注解方式實作AOP
匯入相關jar包,以下作為參考
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
druid-1.1.9.jar
spring-aop-5.2.6.RELEASE.jar
spring-aspects-5.2.6.RELEASE.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.jar
創建普通類
@Component//該注解實作bean注入
public class User {
public void add(){
System.out.println("add....");
}
}
創建增強類,這里展示前置通知,最終通知,后置通知,例外通知和環繞通知
@Component
@Aspect //生成代理物件
public class UserProxy {
//前置通知
@Before(value = "https://www.cnblogs.com/xuzhuo123/p/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void before(){
System.out.println("before....");
}
//最終通知
@After(value = "https://www.cnblogs.com/xuzhuo123/p/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void after(){
System.out.println("after...");
}
//后置通知(回傳通知)
@AfterReturning(value = "https://www.cnblogs.com/xuzhuo123/p/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning...");
}
//例外通知
@AfterThrowing(value = "https://www.cnblogs.com/xuzhuo123/p/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing...");
}
//環繞通知
@Around(value = "https://www.cnblogs.com/xuzhuo123/p/execution(* com.hnust.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("環繞之前");
//執行原方法
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("環繞之后");
}
}
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: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.hnust.spring5"></context:component-scan>
<!--開啟Aspectj生成代理物件-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
創建測驗類
@Test
public void testAopAnno(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}
執行結果:

前置通知,在方法執行之前執行;
最終通知,在方法執行之后執行;
后置通知(回傳通知),在方法回傳結果之后執行;
例外通知,在方法拋出例外之后執行;
環繞通知,圍繞著方法執行,
關于最終通知和后置通知可能會有概念上的區別,以自己學的實際為準,
如果有多個增強類對同一個方法進行增強,可以通過添加注解 @Order(數字)來設定優先級,數字越小,優先級越高,
操作資料庫
Spring 框架對 JDBC 進行封裝,使用 JdbcTemplate 方便實作對資料庫操作
首先引入相關jar包,具體版本根據自己的實際版本為準,以下為參考
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
druid-1.1.9.jar
mysql-connector-java-5.1.7-bin.jar
spring-aop-5.2.6.RELEASE.jar
spring-aspects-5.2.6.RELEASE.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.jar
spring-jdbc-5.2.6.RELEASE.jar
spring-orm-5.2.6.RELEASE.jar
spring-tx-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"
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.hnust.spring5"></context:component-scan>
<!--配置資料庫連接池 -->
<bean id="dataSource"
destroy-method="close">
<property name="url" value="https://www.cnblogs.com/xuzhuo123/p/jdbc:mysql:///user_db" />
<property name="username" value="https://www.cnblogs.com/xuzhuo123/p/root" />
<property name="password" value="https://www.cnblogs.com/xuzhuo123/p/root" />
<property name="driverClassName" value="https://www.cnblogs.com/xuzhuo123/p/com.mysql.jdbc.Driver" />
</bean>
<!--JdbcTemplate物件-->
<bean id="jdbcTemplate" >
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
撰寫dao層代碼,以下示例只展示了dao層的部分實作類,其他的功能大同小異,都學到這里了,service層肯定都會寫,我就不再貼出來了,
@Service
public class BookDaoImpl implements BookDao{
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加
@Override
public void add(Book book) {
String sql = "insert into t_book values(?, ?, ?)";
Object[] args = {book.getUser_id(), book.getUsername(), book.getUstatus()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}
//修改
@Override
public void updateBook(Book book) {
String sql = "update t_book set username=?, ustatus=? where user_id=?";
Object[] args = {book.getUsername(), book.getUstatus(), book.getUser_id()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}
//洗掉
@Override
public void deleteBook(Integer id) {
String sql = "delete from t_book where user_id=?";
int update = jdbcTemplate.update(sql, id);
System.out.println(update);
}
//查詢
@Override
public Book findOne(Integer id) {
String sql = "select * from t_book where user_id=?";
return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class),id);
}
}
測驗
public class TestBook {
@Test
public void testJdbcTemplate(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookServiceImpl bookServiceImpl = context.getBean("bookServiceImpl", BookServiceImpl.class);
//添加
// bookServiceImpl.addBook(new Book(1,"java", "on"){});
//修改
// bookServiceImpl.updateBook(new Book(1,"c++","off"));
//洗掉
// bookServiceImpl.deleteBook(1);
//查詢
// System.out.println(bookServiceImpl.findOne(1));
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/388911.html
標籤:Java
上一篇:一次大資料量匯出優化--借助xml匯出xls、xlsx檔案
下一篇:PDF轉圖片,拼接圖片
